diff --git a/client/pom.xml b/client/pom.xml index 7eafb9726d..12c24f6665 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -47,19 +47,10 @@ - - commons-fileupload - commons-fileupload - 1.6.0 - test - - - - - javax.portlet - portlet-api - 3.0.1 + org.apache.commons + commons-fileupload2-jakarta-servlet5 + 2.0.0-M2 test diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileItem.java b/client/src/test/java/org/apache/commons/fileupload2/FileItem.java deleted file mode 100644 index f9e27bcbac..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileItem.java +++ /dev/null @@ -1,202 +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.commons.fileupload2; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.io.UnsupportedEncodingException; - -/** - *

This class represents a file or form item that was received within a - * {@code multipart/form-data} POST request. - * - *

After retrieving an instance of this class from a {@link - * FileUpload FileUpload} instance (see - * {@link org.apache.commons.fileupload2.servlet.ServletFileUpload - * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may - * either request all contents of the file at once using {@link #get()} or - * request an {@link InputStream InputStream} with - * {@link #getInputStream()} and process the file without attempting to load - * it into memory, which may come handy with large files. - * - *

While this interface does not extend - * {@code javax.activation.DataSource} per se (to avoid a seldom used - * dependency), several of the defined methods are specifically defined with - * the same signatures as methods in that interface. This allows an - * implementation of this interface to also implement - * {@code javax.activation.DataSource} with minimal additional work. - * - * @since 1.3 additionally implements FileItemHeadersSupport - */ -public interface FileItem extends FileItemHeadersSupport { - - // ------------------------------- Methods from javax.activation.DataSource - - /** - * Returns an {@link InputStream InputStream} that can be - * used to retrieve the contents of the file. - * - * @return An {@link InputStream InputStream} that can be - * used to retrieve the contents of the file. - * @throws IOException if an error occurs. - */ - InputStream getInputStream() throws IOException; - - /** - * Returns the content type passed by the browser or {@code null} if - * not defined. - * - * @return The content type passed by the browser or {@code null} if - * not defined. - */ - String getContentType(); - - /** - * Returns the original file name in the client's file system, as provided by - * the browser (or other client software). In most cases, this will be the - * base file name, without path information. However, some clients, such as - * the Opera browser, do include path information. - * - * @return The original file name in the client's file system. - * @throws InvalidFileNameException The file name contains a NUL character, - * which might be an indicator of a security attack. If you intend to - * use the file name anyways, catch the exception and use - * InvalidFileNameException#getName(). - */ - String getName(); - - // ------------------------------------------------------- FileItem methods - - /** - * Provides a hint as to whether or not the file contents will be read - * from memory. - * - * @return {@code true} if the file contents will be read from memory; - * {@code false} otherwise. - */ - boolean isInMemory(); - - /** - * Returns the size of the file item. - * - * @return The size of the file item, in bytes. - */ - long getSize(); - - /** - * Returns the contents of the file item as an array of bytes. - * - * @return The contents of the file item as an array of bytes. - * @throws UncheckedIOException if an I/O error occurs - */ - byte[] get() throws UncheckedIOException; - - /** - * Returns the contents of the file item as a String, using the specified - * encoding. This method uses {@link #get()} to retrieve the - * contents of the item. - * - * @param encoding The character encoding to use. - * @return The contents of the item, as a string. - * @throws UnsupportedEncodingException if the requested character - * encoding is not available. - * @throws IOException if an I/O error occurs - */ - String getString(String encoding) throws UnsupportedEncodingException, IOException; - - /** - * Returns the contents of the file item as a String, using the default - * character encoding. This method uses {@link #get()} to retrieve the - * contents of the item. - * - * @return The contents of the item, as a string. - */ - String getString(); - - /** - * 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 method is not guaranteed to succeed if called more than once for - * the same item. This allows a particular implementation to use, for - * example, file renaming, where possible, rather than copying all of the - * underlying data, thus gaining a significant performance benefit. - * - * @param file The {@code File} into which the uploaded item should - * be stored. - * @throws Exception if an error occurs. - */ - void write(File file) throws Exception; - - /** - * Deletes the underlying storage for a file item, including deleting any - * associated temporary disk file. Although this storage will be deleted - * automatically when the {@code FileItem} instance is garbage - * collected, this method can be used to ensure that this is done at an - * earlier time, thus preserving system resources. - */ - void delete(); - - /** - * Returns the name of the field in the multipart form corresponding to - * this file item. - * - * @return The name of the form field. - */ - String getFieldName(); - - /** - * Sets the field name used to reference this file item. - * - * @param name The name of the form field. - */ - void setFieldName(String name); - - /** - * Determines whether or not a {@code FileItem} instance represents - * a simple form field. - * - * @return {@code true} if the instance represents a simple form - * field; {@code false} if it represents an uploaded file. - */ - boolean isFormField(); - - /** - * Specifies whether or not a {@code FileItem} instance represents - * a simple form field. - * - * @param state {@code true} if the instance represents a simple form - * field; {@code false} if it represents an uploaded file. - */ - void setFormField(boolean state); - - /** - * Returns an {@link OutputStream OutputStream} that can - * be used for storing the contents of the file. - * - * @return An {@link OutputStream OutputStream} that can be used - * for storing the contents of the file. - * @throws IOException if an error occurs. - */ - OutputStream getOutputStream() throws IOException; - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileItemFactory.java b/client/src/test/java/org/apache/commons/fileupload2/FileItemFactory.java deleted file mode 100644 index 6ba1d1ecac..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileItemFactory.java +++ /dev/null @@ -1,45 +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.commons.fileupload2; - -/** - *

A factory interface for creating {@link FileItem} instances. Factories - * can provide their own custom configuration, over and above that provided - * by the default file upload implementation.

- */ -public interface FileItemFactory { - - /** - * Create a new {@link FileItem} instance from the supplied parameters and - * any local factory configuration. - * - * @param fieldName The name of the form field. - * @param contentType The content type of the form field. - * @param isFormField {@code true} if this is a plain form field; - * {@code 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. - */ - FileItem createItem( - String fieldName, - String contentType, - boolean isFormField, - String fileName - ); - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileItemHeaders.java b/client/src/test/java/org/apache/commons/fileupload2/FileItemHeaders.java deleted file mode 100644 index 2f9e7ceae1..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileItemHeaders.java +++ /dev/null @@ -1,74 +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.commons.fileupload2; - -import java.util.Iterator; - -/** - *

This class provides support for accessing the headers for a file or form - * item that was received within a {@code multipart/form-data} POST - * request.

- * - * @since 1.2.1 - */ -public interface FileItemHeaders { - - /** - * Returns the value of the specified part header as a {@code String}. - *

- * If the part did not include a header of the specified name, this method - * return {@code null}. If there are multiple headers with the same - * name, this method returns the first header in the item. The header - * name is case insensitive. - * - * @param name a {@code String} specifying the header name - * @return a {@code String} containing the value of the requested - * header, or {@code null} if the item does not have a header - * of that name - */ - String getHeader(String name); - - /** - *

- * Returns all the values of the specified item header as an - * {@code Iterator} of {@code String} objects. - *

- *

- * If the item did not include any headers of the specified name, this - * method returns an empty {@code Iterator}. The header name is - * case insensitive. - *

- * - * @param name a {@code String} specifying the header name - * @return an {@code Iterator} containing the values of the - * requested header. If the item does not have any headers of - * that name, return an empty {@code Iterator} - */ - Iterator getHeaders(String name); - - /** - *

- * Returns an {@code Iterator} of all the header names. - *

- * - * @return an {@code Iterator} containing all of the names of - * headers provided with this file item. If the item does not have - * any headers return an empty {@code Iterator} - */ - Iterator getHeaderNames(); - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileItemHeadersSupport.java b/client/src/test/java/org/apache/commons/fileupload2/FileItemHeadersSupport.java deleted file mode 100644 index 61b96007f6..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileItemHeadersSupport.java +++ /dev/null @@ -1,47 +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.commons.fileupload2; - -/** - * Interface that will indicate that {@link FileItem} or {@link FileItemStream} - * implementations will accept the headers read for the item. - * - * @see FileItem - * @see FileItemStream - * @since 1.2.1 - */ -public interface FileItemHeadersSupport { - - /** - * Returns the collection of headers defined locally within this item. - * - * @return the {@link FileItemHeaders} present for this item. - */ - FileItemHeaders getHeaders(); - - /** - * Sets the headers read from within an item. Implementations of - * {@link FileItem} or {@link FileItemStream} should implement this - * interface to be able to get the raw headers found within the item - * header block. - * - * @param headers the instance that holds onto the headers - * for this instance. - */ - void setHeaders(FileItemHeaders headers); - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileItemIterator.java b/client/src/test/java/org/apache/commons/fileupload2/FileItemIterator.java deleted file mode 100644 index b3e1703f5c..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileItemIterator.java +++ /dev/null @@ -1,105 +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.commons.fileupload2; - -import org.apache.commons.fileupload2.pub.FileSizeLimitExceededException; -import org.apache.commons.fileupload2.pub.SizeLimitExceededException; - -import java.io.IOException; -import java.util.List; - -/** - * An iterator, as returned by - * {@link FileUploadBase#getItemIterator(RequestContext)}. - */ -public interface FileItemIterator { - /** - * Returns the maximum size of a single file. An {@link FileSizeLimitExceededException} - * will be thrown, if there is an uploaded file, which is exceeding this value. - * By default, this value will be copied from the {@link FileUploadBase#getFileSizeMax() - * FileUploadBase} object, however, the user may replace the default value with a - * request specific value by invoking {@link #setFileSizeMax(long)} on this object. - * - * @return The maximum size of a single, uploaded file. The value -1 indicates "unlimited". - */ - long getFileSizeMax(); - - /** - * Sets the maximum size of a single file. An {@link FileSizeLimitExceededException} - * will be thrown, if there is an uploaded file, which is exceeding this value. - * By default, this value will be copied from the {@link FileUploadBase#getFileSizeMax() - * FileUploadBase} object, however, the user may replace the default value with a - * request specific value by invoking {@link #setFileSizeMax(long)} on this object, so - * there is no need to configure it here. - * Note:Changing this value doesn't affect files, that have already been uploaded. - * - * @param pFileSizeMax The maximum size of a single, uploaded file. The value -1 indicates "unlimited". - */ - void setFileSizeMax(long pFileSizeMax); - - /** - * Returns the maximum size of the complete HTTP request. A {@link SizeLimitExceededException} - * will be thrown, if the HTTP request will exceed this value. - * By default, this value will be copied from the {@link FileUploadBase#getSizeMax() - * FileUploadBase} object, however, the user may replace the default value with a - * request specific value by invoking {@link #setSizeMax(long)} on this object. - * - * @return The maximum size of the complete HTTP request. The value -1 indicates "unlimited". - */ - long getSizeMax(); - - /** - * Returns the maximum size of the complete HTTP request. A {@link SizeLimitExceededException} - * will be thrown, if the HTTP request will exceed this value. - * By default, this value will be copied from the {@link FileUploadBase#getSizeMax() - * FileUploadBase} object, however, the user may replace the default value with a - * request specific value by invoking {@link #setSizeMax(long)} on this object. - * Note: Setting the maximum size on this object will work only, if the iterator is not - * yet initialized. In other words: If the methods {@link #hasNext()}, {@link #next()} have not - * yet been invoked. - * - * @param pSizeMax The maximum size of the complete HTTP request. The value -1 indicates "unlimited". - */ - void setSizeMax(long pSizeMax); - - /** - * Returns, whether another instance of {@link FileItemStream} - * is available. - * - * @return True, if one or more additional file items - * are available, otherwise false. - * @throws FileUploadException Parsing or processing the - * file item failed. - * @throws IOException Reading the file item failed. - */ - boolean hasNext() throws FileUploadException, IOException; - - /** - * Returns the next available {@link FileItemStream}. - * - * @return FileItemStream instance, which provides - * access to the next file item. - * @throws java.util.NoSuchElementException No more items are available. Use - * {@link #hasNext()} to prevent this exception. - * @throws FileUploadException Parsing or processing the - * file item failed. - * @throws IOException Reading the file item failed. - */ - FileItemStream next() throws FileUploadException, IOException; - - List getFileItems() throws FileUploadException, IOException; -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileItemStream.java b/client/src/test/java/org/apache/commons/fileupload2/FileItemStream.java deleted file mode 100644 index c72c832073..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileItemStream.java +++ /dev/null @@ -1,102 +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.commons.fileupload2; - -import java.io.IOException; -import java.io.InputStream; - -/** - *

This interface provides access to a file or form item that was - * received within a {@code multipart/form-data} POST request. - * The items contents are retrieved by calling {@link #openStream()}.

- *

Instances of this class are created by accessing the - * iterator, returned by - * {@link FileUploadBase#getItemIterator(RequestContext)}.

- *

Note: There is an interaction between the iterator and - * its associated instances of {@link FileItemStream}: By invoking - * {@link java.util.Iterator#hasNext()} on the iterator, you discard all data, - * which hasn't been read so far from the previous data.

- */ -public interface FileItemStream extends FileItemHeadersSupport { - - /** - * This exception is thrown, if an attempt is made to read - * data from the {@link InputStream}, which has been returned - * by {@link FileItemStream#openStream()}, after - * {@link java.util.Iterator#hasNext()} has been invoked on the - * iterator, which created the {@link FileItemStream}. - */ - class ItemSkippedException extends IOException { - - /** - * The exceptions serial version UID, which is being used - * when serializing an exception instance. - */ - private static final long serialVersionUID = -7280778431581963740L; - - } - - /** - * Creates an {@link InputStream}, which allows to read the - * items contents. - * - * @return The input stream, from which the items data may - * be read. - * @throws IllegalStateException The method was already invoked on - * this item. It is not possible to recreate the data stream. - * @throws IOException An I/O error occurred. - * @see ItemSkippedException - */ - InputStream openStream() throws IOException; - - /** - * Returns the content type passed by the browser or {@code null} if - * not defined. - * - * @return The content type passed by the browser or {@code null} if - * not defined. - */ - String getContentType(); - - /** - * Returns the original file name in the client's file system, as provided by - * the browser (or other client software). In most cases, this will be the - * base file name, without path information. However, some clients, such as - * the Opera browser, do include path information. - * - * @return The original file name in the client's file system. - */ - String getName(); - - /** - * Returns the name of the field in the multipart form corresponding to - * this file item. - * - * @return The name of the form field. - */ - String getFieldName(); - - /** - * Determines whether or not a {@code FileItem} instance represents - * a simple form field. - * - * @return {@code true} if the instance represents a simple form - * field; {@code false} if it represents an uploaded file. - */ - boolean isFormField(); - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileUpload.java b/client/src/test/java/org/apache/commons/fileupload2/FileUpload.java deleted file mode 100644 index 45a0312e13..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileUpload.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.commons.fileupload2; - -/** - *

High level API for processing file uploads.

- * - *

This class handles multiple files per single HTML widget, sent using - * {@code multipart/mixed} encoding type, as specified by - * RFC 1867. Use {@link - * #parseRequest(RequestContext)} to acquire a list - * of {@link FileItem FileItems} 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.

- */ -public class FileUpload - extends FileUploadBase { - - // ----------------------------------------------------------- Data members - - /** - * The factory to use to create new form items. - */ - private FileItemFactory fileItemFactory; - - // ----------------------------------------------------------- Constructors - - /** - * Constructs an uninitialized instance of this class. - *

- * A factory must be - * configured, using {@code setFileItemFactory()}, before attempting - * to parse requests. - * - * @see #FileUpload(FileItemFactory) - */ - public FileUpload() { - } - - /** - * Constructs an instance of this class which uses the supplied factory to - * create {@code FileItem} instances. - * - * @param fileItemFactory The factory to use for creating file items. - * @see #FileUpload() - */ - public FileUpload(final FileItemFactory fileItemFactory) { - this.fileItemFactory = fileItemFactory; - } - - // ----------------------------------------------------- Property accessors - - /** - * Returns the factory class used when creating file items. - * - * @return The factory class for new file items. - */ - @Override - public FileItemFactory getFileItemFactory() { - return fileItemFactory; - } - - /** - * Sets the factory class to use when creating file items. - * - * @param factory The factory class for new file items. - */ - @Override - public void setFileItemFactory(final FileItemFactory factory) { - this.fileItemFactory = factory; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileUploadBase.java b/client/src/test/java/org/apache/commons/fileupload2/FileUploadBase.java deleted file mode 100644 index d375518eb7..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileUploadBase.java +++ /dev/null @@ -1,651 +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.commons.fileupload2; - -import org.apache.commons.fileupload2.impl.FileItemIteratorImpl; -import org.apache.commons.fileupload2.pub.FileUploadIOException; -import org.apache.commons.fileupload2.pub.IOFileUploadException; -import org.apache.commons.fileupload2.util.FileItemHeadersImpl; -import org.apache.commons.fileupload2.util.Streams; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; - -import static java.lang.String.format; - -/** - *

High level API for processing file uploads.

- * - *

This class handles multiple files per single HTML widget, sent using - * {@code multipart/mixed} encoding type, as specified by - * RFC 1867. Use {@link - * #parseRequest(RequestContext)} to acquire a list of {@link - * 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.

- */ -public abstract class FileUploadBase { - - // ---------------------------------------------------------- Class methods - - /** - *

Utility method that determines whether the request contains multipart - * content.

- * - *

NOTE:This method will be moved to the - * {@code ServletFileUpload} class after the FileUpload 1.1 release. - * Unfortunately, since this method is static, it is not possible to - * provide its replacement until this method is removed.

- * - * @param ctx The request context to be evaluated. Must be non-null. - * @return {@code true} if the request is multipart; - * {@code false} otherwise. - */ - public static final boolean isMultipartContent(final RequestContext ctx) { - final String contentType = ctx.getContentType(); - if (contentType == null) { - return false; - } - return contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART); - } - - // ----------------------------------------------------- Manifest constants - - /** - * HTTP content type header name. - */ - public static final String CONTENT_TYPE = "Content-type"; - - /** - * HTTP content disposition header name. - */ - public static final String CONTENT_DISPOSITION = "Content-disposition"; - - /** - * HTTP content length header name. - */ - public static final String CONTENT_LENGTH = "Content-length"; - - /** - * Content-disposition value for form data. - */ - public static final String FORM_DATA = "form-data"; - - /** - * Content-disposition value for file attachment. - */ - public static final String ATTACHMENT = "attachment"; - - /** - * Part of HTTP content type header. - */ - public static final String MULTIPART = "multipart/"; - - /** - * HTTP content type header for multipart forms. - */ - public static final String MULTIPART_FORM_DATA = "multipart/form-data"; - - /** - * HTTP content type header for multiple uploads. - */ - public static final String MULTIPART_MIXED = "multipart/mixed"; - - /** - * The maximum length of a single header line that will be parsed - * (1024 bytes). - * - * @deprecated This constant is no longer used. As of commons-fileupload - * 1.2, the only applicable limit is the total size of a parts headers, - * {@link MultipartStream#HEADER_PART_SIZE_MAX}. - */ - @Deprecated - public static final int MAX_HEADER_SIZE = 1024; - - // ----------------------------------------------------------- Data members - - /** - * The maximum size permitted for the complete request, as opposed to - * {@link #fileSizeMax}. A value of -1 indicates no maximum. - */ - private long sizeMax = -1; - - /** - * The maximum size permitted for a single uploaded file, as opposed - * to {@link #sizeMax}. A value of -1 indicates no maximum. - */ - private long fileSizeMax = -1; - - /** - * The content encoding to use when reading part headers. - */ - private String headerEncoding; - - /** - * The progress listener. - */ - private ProgressListener listener; - - // ----------------------------------------------------- Property accessors - - /** - * Returns the factory class used when creating file items. - * - * @return The factory class for new file items. - */ - public abstract FileItemFactory getFileItemFactory(); - - /** - * Sets the factory class to use when creating file items. - * - * @param factory The factory class for new file items. - */ - public abstract void setFileItemFactory(FileItemFactory factory); - - /** - * Returns the maximum allowed size of a complete request, as opposed - * to {@link #getFileSizeMax()}. - * - * @return The maximum allowed size, in bytes. The default value of - * -1 indicates, that there is no limit. - * @see #setSizeMax(long) - */ - public long getSizeMax() { - return sizeMax; - } - - /** - * Sets the maximum allowed size of a complete request, as opposed - * to {@link #setFileSizeMax(long)}. - * - * @param sizeMax The maximum allowed size, in bytes. The default value of - * -1 indicates, that there is no limit. - * @see #getSizeMax() - */ - public void setSizeMax(final long sizeMax) { - this.sizeMax = sizeMax; - } - - /** - * Returns the maximum allowed size of a single uploaded file, - * as opposed to {@link #getSizeMax()}. - * - * @return Maximum size of a single uploaded file. - * @see #setFileSizeMax(long) - */ - public long getFileSizeMax() { - return fileSizeMax; - } - - /** - * Sets the maximum allowed size of a single uploaded file, - * as opposed to {@link #getSizeMax()}. - * - * @param fileSizeMax Maximum size of a single uploaded file. - * @see #getFileSizeMax() - */ - public void setFileSizeMax(final long fileSizeMax) { - this.fileSizeMax = fileSizeMax; - } - - /** - * Retrieves the character encoding used when reading the headers of an - * individual part. When not specified, or {@code null}, the request - * encoding is used. If that is also not specified, or {@code null}, - * the platform default encoding is used. - * - * @return The encoding used to read part headers. - */ - public String getHeaderEncoding() { - return headerEncoding; - } - - /** - * Specifies the character encoding to be used when reading the headers of - * individual part. When not specified, or {@code null}, the request - * encoding is used. If that is also not specified, or {@code null}, - * the platform default encoding is used. - * - * @param encoding The encoding used to read part headers. - */ - public void setHeaderEncoding(final String encoding) { - headerEncoding = encoding; - } - - // --------------------------------------------------------- Public methods - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param ctx The context for the request to be parsed. - * @return An iterator to instances of {@code 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(final RequestContext ctx) - throws FileUploadException, IOException { - try { - return new FileItemIteratorImpl(this, ctx); - } catch (final FileUploadIOException e) { - // unwrap encapsulated SizeException - throw (FileUploadException) e.getCause(); - } - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param ctx The context for the request to be parsed. - * @return A list of {@code 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(final RequestContext ctx) - throws FileUploadException { - final List items = new ArrayList<>(); - boolean successful = false; - try { - final FileItemIterator iter = getItemIterator(ctx); - final FileItemFactory fileItemFactory = Objects.requireNonNull(getFileItemFactory(), - "No FileItemFactory has been set."); - final byte[] buffer = new byte[Streams.DEFAULT_BUFFER_SIZE]; - while (iter.hasNext()) { - final FileItemStream item = iter.next(); - // Don't use getName() here to prevent an InvalidFileNameException. - final String fileName = item.getName(); - final FileItem fileItem = fileItemFactory.createItem(item.getFieldName(), item.getContentType(), - item.isFormField(), fileName); - items.add(fileItem); - try { - Streams.copy(item.openStream(), fileItem.getOutputStream(), true, buffer); - } catch (final FileUploadIOException e) { - throw (FileUploadException) e.getCause(); - } catch (final IOException e) { - throw new IOFileUploadException(format("Processing of %s request failed. %s", - MULTIPART_FORM_DATA, e.getMessage()), e); - } - final FileItemHeaders fih = item.getHeaders(); - fileItem.setHeaders(fih); - } - successful = true; - return items; - } catch (final FileUploadException e) { - throw e; - } catch (final IOException e) { - throw new FileUploadException(e.getMessage(), e); - } finally { - if (!successful) { - for (final FileItem fileItem : items) { - try { - fileItem.delete(); - } catch (final Exception ignored) { - // ignored TODO perhaps add to tracker delete failure list somehow? - } - } - } - } - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param ctx The context for the request to be parsed. - * @return A map of {@code FileItem} instances parsed from the request. - * @throws FileUploadException if there are problems reading/parsing - * the request or storing files. - * @since 1.3 - */ - public Map> parseParameterMap(final RequestContext ctx) - throws FileUploadException { - final List items = parseRequest(ctx); - final Map> itemsMap = new HashMap<>(items.size()); - - for (final FileItem fileItem : items) { - final String fieldName = fileItem.getFieldName(); - final List mappedItems = itemsMap.computeIfAbsent(fieldName, k -> new ArrayList<>()); - - mappedItems.add(fileItem); - } - - return itemsMap; - } - - // ------------------------------------------------------ Protected methods - - /** - * Retrieves the boundary from the {@code Content-type} header. - * - * @param contentType The value of the content type header from which to - * extract the boundary value. - * @return The boundary, as a byte array. - */ - public byte[] getBoundary(final String contentType) { - final ParameterParser parser = new ParameterParser(); - parser.setLowerCaseNames(true); - // Parameter parser can handle null input - final Map params = parser.parse(contentType, new char[]{';', ','}); - final String boundaryStr = params.get("boundary"); - - if (boundaryStr == null) { - return null; - } - final byte[] boundary; - boundary = boundaryStr.getBytes(StandardCharsets.ISO_8859_1); - return boundary; - } - - /** - * Retrieves the file name from the {@code Content-disposition} - * header. - * - * @param headers A {@code Map} containing the HTTP request headers. - * @return The file name for the current {@code encapsulation}. - * @deprecated 1.2.1 Use {@link #getFileName(FileItemHeaders)}. - */ - @Deprecated - protected String getFileName(final Map headers) { - return getFileName(getHeader(headers, CONTENT_DISPOSITION)); - } - - /** - * Retrieves the file name from the {@code Content-disposition} - * header. - * - * @param headers The HTTP headers object. - * @return The file name for the current {@code encapsulation}. - */ - public String getFileName(final FileItemHeaders headers) { - return getFileName(headers.getHeader(CONTENT_DISPOSITION)); - } - - /** - * Returns the given content-disposition headers file name. - * - * @param pContentDisposition The content-disposition headers value. - * @return The file name - */ - private String getFileName(final String pContentDisposition) { - String fileName = null; - if (pContentDisposition != null) { - final String cdl = pContentDisposition.toLowerCase(Locale.ENGLISH); - if (cdl.startsWith(FORM_DATA) || cdl.startsWith(ATTACHMENT)) { - final ParameterParser parser = new ParameterParser(); - parser.setLowerCaseNames(true); - // Parameter parser can handle null input - final Map params = parser.parse(pContentDisposition, ';'); - if (params.containsKey("filename")) { - fileName = params.get("filename"); - if (fileName != null) { - fileName = fileName.trim(); - } else { - // Even if there is no value, the parameter is present, - // so we return an empty file name rather than no file - // name. - fileName = ""; - } - } - } - } - return fileName; - } - - /** - * Retrieves the field name from the {@code Content-disposition} - * header. - * - * @param headers A {@code Map} containing the HTTP request headers. - * @return The field name for the current {@code encapsulation}. - */ - public String getFieldName(final FileItemHeaders headers) { - return getFieldName(headers.getHeader(CONTENT_DISPOSITION)); - } - - /** - * Returns the field name, which is given by the content-disposition - * header. - * - * @param pContentDisposition The content-dispositions header value. - * @return The field jake - */ - private String getFieldName(final String pContentDisposition) { - String fieldName = null; - if (pContentDisposition != null - && pContentDisposition.toLowerCase(Locale.ENGLISH).startsWith(FORM_DATA)) { - final ParameterParser parser = new ParameterParser(); - parser.setLowerCaseNames(true); - // Parameter parser can handle null input - final Map params = parser.parse(pContentDisposition, ';'); - fieldName = params.get("name"); - if (fieldName != null) { - fieldName = fieldName.trim(); - } - } - return fieldName; - } - - /** - * Retrieves the field name from the {@code Content-disposition} - * header. - * - * @param headers A {@code Map} containing the HTTP request headers. - * @return The field name for the current {@code encapsulation}. - * @deprecated 1.2.1 Use {@link #getFieldName(FileItemHeaders)}. - */ - @Deprecated - protected String getFieldName(final Map headers) { - return getFieldName(getHeader(headers, CONTENT_DISPOSITION)); - } - - /** - * Creates a new {@link FileItem} instance. - * - * @param headers A {@code Map} containing the HTTP request - * headers. - * @param isFormField Whether or not this item is a form field, as - * opposed to a file. - * @return A newly created {@code FileItem} instance. - * @throws FileUploadException if an error occurs. - * @deprecated 1.2 This method is no longer used in favour of - * internally created instances of {@link FileItem}. - */ - @Deprecated - protected FileItem createItem(final Map headers, - final boolean isFormField) - throws FileUploadException { - return getFileItemFactory().createItem(getFieldName(headers), - getHeader(headers, CONTENT_TYPE), - isFormField, - getFileName(headers)); - } - - /** - *

Parses the {@code header-part} and returns as key/value - * pairs. - * - *

If there are multiple headers of the same names, the name - * will map to a comma-separated list containing the values. - * - * @param headerPart The {@code header-part} of the current - * {@code encapsulation}. - * @return A {@code Map} containing the parsed HTTP request headers. - */ - public FileItemHeaders getParsedHeaders(final String headerPart) { - final int len = headerPart.length(); - final FileItemHeadersImpl headers = newFileItemHeaders(); - int start = 0; - for (; ; ) { - int end = parseEndOfLine(headerPart, start); - if (start == end) { - break; - } - final StringBuilder header = new StringBuilder(headerPart.substring(start, end)); - start = end + 2; - while (start < len) { - int nonWs = start; - while (nonWs < len) { - final char c = headerPart.charAt(nonWs); - if (c != ' ' && c != '\t') { - break; - } - ++nonWs; - } - if (nonWs == start) { - break; - } - // Continuation line found - end = parseEndOfLine(headerPart, nonWs); - header.append(' ').append(headerPart, nonWs, end); - start = end + 2; - } - parseHeaderLine(headers, header.toString()); - } - return headers; - } - - /** - * Creates a new instance of {@link FileItemHeaders}. - * - * @return The new instance. - */ - protected FileItemHeadersImpl newFileItemHeaders() { - return new FileItemHeadersImpl(); - } - - /** - *

Parses the {@code header-part} and returns as key/value - * pairs. - * - *

If there are multiple headers of the same names, the name - * will map to a comma-separated list containing the values. - * - * @param headerPart The {@code header-part} of the current - * {@code encapsulation}. - * @return A {@code Map} containing the parsed HTTP request headers. - * @deprecated 1.2.1 Use {@link #getParsedHeaders(String)} - */ - @Deprecated - protected Map parseHeaders(final String headerPart) { - final FileItemHeaders headers = getParsedHeaders(headerPart); - final Map result = new HashMap<>(); - for (final Iterator iter = headers.getHeaderNames(); iter.hasNext(); ) { - final String headerName = iter.next(); - final Iterator iter2 = headers.getHeaders(headerName); - final StringBuilder headerValue = new StringBuilder(iter2.next()); - while (iter2.hasNext()) { - headerValue.append(",").append(iter2.next()); - } - result.put(headerName, headerValue.toString()); - } - return result; - } - - /** - * Skips bytes until the end of the current line. - * - * @param headerPart The headers, which are being parsed. - * @param end Index of the last byte, which has yet been - * processed. - * @return Index of the \r\n sequence, which indicates - * end of line. - */ - private int parseEndOfLine(final String headerPart, final int end) { - int index = end; - for (; ; ) { - final int offset = headerPart.indexOf('\r', index); - if (offset == -1 || offset + 1 >= headerPart.length()) { - throw new IllegalStateException( - "Expected headers to be terminated by an empty line."); - } - if (headerPart.charAt(offset + 1) == '\n') { - return offset; - } - index = offset + 1; - } - } - - /** - * Reads the next header line. - * - * @param headers String with all headers. - * @param header Map where to store the current header. - */ - private void parseHeaderLine(final FileItemHeadersImpl headers, final String header) { - final int colonOffset = header.indexOf(':'); - if (colonOffset == -1) { - // This header line is malformed, skip it. - return; - } - final String headerName = header.substring(0, colonOffset).trim(); - final String headerValue = - header.substring(colonOffset + 1).trim(); - headers.addHeader(headerName, headerValue); - } - - /** - * Returns the header with the specified name from the supplied map. The - * header lookup is case-insensitive. - * - * @param headers A {@code Map} containing the HTTP request headers. - * @param name The name of the header to return. - * @return The value of specified header, or a comma-separated list if - * there were multiple headers of that name. - * @deprecated 1.2.1 Use {@link FileItemHeaders#getHeader(String)}. - */ - @Deprecated - protected final String getHeader(final Map headers, - final String name) { - return headers.get(name.toLowerCase(Locale.ENGLISH)); - } - - /** - * Returns the progress listener. - * - * @return The progress listener, if any, or null. - */ - public ProgressListener getProgressListener() { - return listener; - } - - /** - * Sets the progress listener. - * - * @param pListener The progress listener, if any. Defaults to null. - */ - public void setProgressListener(final ProgressListener pListener) { - listener = pListener; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/FileUploadException.java b/client/src/test/java/org/apache/commons/fileupload2/FileUploadException.java deleted file mode 100644 index ba46272af8..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/FileUploadException.java +++ /dev/null @@ -1,106 +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.commons.fileupload2; - -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; - -/** - * Exception for errors encountered while processing the request. - */ -public class FileUploadException extends IOException { - - /** - * Serial version UID, being used, if the exception - * is serialized. - */ - private static final long serialVersionUID = 8881893724388807504L; - - /** - * The exceptions cause. We overwrite the cause of - * the super class, which isn't available in Java 1.3. - */ - private final Throwable cause; - - /** - * Constructs a new {@code FileUploadException} without message. - */ - public FileUploadException() { - this(null, null); - } - - /** - * Constructs a new {@code FileUploadException} with specified detail - * message. - * - * @param msg the error message. - */ - public FileUploadException(final String msg) { - this(msg, null); - } - - /** - * Creates a new {@code FileUploadException} with the given - * detail message and cause. - * - * @param msg The exceptions detail message. - * @param cause The exceptions cause. - */ - public FileUploadException(final String msg, final Throwable cause) { - super(msg); - this.cause = cause; - } - - /** - * Prints this throwable and its backtrace to the specified print stream. - * - * @param stream {@code PrintStream} to use for output - */ - @Override - public void printStackTrace(final PrintStream stream) { - super.printStackTrace(stream); - if (cause != null) { - stream.println("Caused by:"); - cause.printStackTrace(stream); - } - } - - /** - * Prints this throwable and its backtrace to the specified - * print writer. - * - * @param writer {@code PrintWriter} to use for output - */ - @Override - public void printStackTrace(final PrintWriter writer) { - super.printStackTrace(writer); - if (cause != null) { - writer.println("Caused by:"); - cause.printStackTrace(writer); - } - } - - /** - * {@inheritDoc} - */ - @Override - public Throwable getCause() { - return cause; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/InvalidFileNameException.java b/client/src/test/java/org/apache/commons/fileupload2/InvalidFileNameException.java deleted file mode 100644 index 3b940be1ef..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/InvalidFileNameException.java +++ /dev/null @@ -1,62 +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.commons.fileupload2; - -/** - * This exception is thrown in case of an invalid file name. - * A file name is invalid, if it contains a NUL character. - * Attackers might use this to circumvent security checks: - * For example, a malicious user might upload a file with the name - * "foo.exe\0.png". This file name might pass security checks (i.e. - * checks for the extension ".png"), while, depending on the underlying - * C library, it might create a file named "foo.exe", as the NUL - * character is the string terminator in C. - */ -public class InvalidFileNameException extends RuntimeException { - - /** - * Serial version UID, being used, if the exception - * is serialized. - */ - private static final long serialVersionUID = 7922042602454350470L; - - /** - * The file name causing the exception. - */ - private final String name; - - /** - * Creates a new instance. - * - * @param pName The file name causing the exception. - * @param pMessage A human readable error message. - */ - public InvalidFileNameException(final String pName, final String pMessage) { - super(pMessage); - name = pName; - } - - /** - * Returns the invalid file name. - * - * @return the invalid file name. - */ - public String getName() { - return name; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/MultipartStream.java b/client/src/test/java/org/apache/commons/fileupload2/MultipartStream.java deleted file mode 100644 index 4198a37ba0..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/MultipartStream.java +++ /dev/null @@ -1,1044 +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.commons.fileupload2; - -import org.apache.commons.fileupload2.pub.FileUploadIOException; -import org.apache.commons.fileupload2.util.Closeable; -import org.apache.commons.fileupload2.util.Streams; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; - -import static java.lang.String.format; - -/** - *

Low level API for processing file uploads. - * - *

This class can be used to process data streams conforming to MIME - * 'multipart' format as defined in - * RFC 1867. Arbitrarily - * large amounts of data in the stream can be processed under constant - * memory usage. - * - *

The format of the stream is defined in the following way:
- * - * - * multipart-body := preamble 1*encapsulation close-delimiter epilogue
- * encapsulation := delimiter body CRLF
- * delimiter := "--" boundary CRLF
- * close-delimiter := "--" boundary "--"
- * preamble := <ignore>
- * epilogue := <ignore>
- * body := header-part CRLF body-part
- * header-part := 1*header CRLF
- * header := header-name ":" header-value
- * header-name := <printable ascii characters except ":">
- * header-value := <any ascii characters except CR & LF>
- * body-data := <arbitrary data>
- *
- * - *

Note that body-data can contain another mulipart entity. There - * is limited support for single pass processing of such nested - * streams. The nested stream is required to have a - * boundary token of the same length as the parent stream (see {@link - * #setBoundary(byte[])}). - * - *

Here is an example of usage of this class.
- * - *

- *   try {
- *     MultipartStream multipartStream = new MultipartStream(input, boundary);
- *     boolean nextPart = multipartStream.skipPreamble();
- *     OutputStream output;
- *     while(nextPart) {
- *       String header = multipartStream.readHeaders();
- *       // process headers
- *       // create some output stream
- *       multipartStream.readBodyData(output);
- *       nextPart = multipartStream.readBoundary();
- *     }
- *   } catch(MultipartStream.MalformedStreamException e) {
- *     // the stream failed to follow required syntax
- *   } catch(IOException e) {
- *     // a read or write error occurred
- *   }
- * 
- */ -public class MultipartStream { - - /** - * Internal class, which is used to invoke the - * {@link ProgressListener}. - */ - public static class ProgressNotifier { - - /** - * The listener to invoke. - */ - private final ProgressListener listener; - - /** - * Number of expected bytes, if known, or -1. - */ - private final long contentLength; - - /** - * Number of bytes, which have been read so far. - */ - private long bytesRead; - - /** - * Number of items, which have been read so far. - */ - private int items; - - /** - * Creates a new instance with the given listener - * and content length. - * - * @param pListener The listener to invoke. - * @param pContentLength The expected content length. - */ - public ProgressNotifier(final ProgressListener pListener, final long pContentLength) { - listener = pListener; - contentLength = pContentLength; - } - - /** - * Called to indicate that bytes have been read. - * - * @param pBytes Number of bytes, which have been read. - */ - void noteBytesRead(final int pBytes) { - /* Indicates, that the given number of bytes have been read from - * the input stream. - */ - bytesRead += pBytes; - notifyListener(); - } - - /** - * Called to indicate, that a new file item has been detected. - */ - public void noteItem() { - ++items; - notifyListener(); - } - - /** - * Called for notifying the listener. - */ - private void notifyListener() { - if (listener != null) { - listener.update(bytesRead, contentLength, items); - } - } - - } - - // ----------------------------------------------------- Manifest constants - - /** - * The Carriage Return ASCII character value. - */ - public static final byte CR = 0x0D; - - /** - * The Line Feed ASCII character value. - */ - public static final byte LF = 0x0A; - - /** - * The dash (-) ASCII character value. - */ - public static final byte DASH = 0x2D; - - /** - * The maximum length of {@code header-part} that will be - * processed (10 kilobytes = 10240 bytes.). - */ - public static final int HEADER_PART_SIZE_MAX = 10240; - - /** - * The default length of the buffer used for processing a request. - */ - protected static final int DEFAULT_BUFSIZE = 4096; - - /** - * A byte sequence that marks the end of {@code header-part} - * ({@code CRLFCRLF}). - */ - protected static final byte[] HEADER_SEPARATOR = {CR, LF, CR, LF}; - - /** - * A byte sequence that that follows a delimiter that will be - * followed by an encapsulation ({@code CRLF}). - */ - protected static final byte[] FIELD_SEPARATOR = {CR, LF}; - - /** - * A byte sequence that that follows a delimiter of the last - * encapsulation in the stream ({@code --}). - */ - protected static final byte[] STREAM_TERMINATOR = {DASH, DASH}; - - /** - * A byte sequence that precedes a boundary ({@code CRLF--}). - */ - protected static final byte[] BOUNDARY_PREFIX = {CR, LF, DASH, DASH}; - - // ----------------------------------------------------------- Data members - - /** - * The input stream from which data is read. - */ - private final InputStream input; - - /** - * The length of the boundary token plus the leading {@code CRLF--}. - */ - private int boundaryLength; - - /** - * The amount of data, in bytes, that must be kept in the buffer in order - * to detect delimiters reliably. - */ - private final int keepRegion; - - /** - * The byte sequence that partitions the stream. - */ - private final byte[] boundary; - - /** - * The table for Knuth-Morris-Pratt search algorithm. - */ - private final int[] boundaryTable; - - /** - * The length of the buffer used for processing the request. - */ - private final int bufSize; - - /** - * The buffer used for processing the request. - */ - private final byte[] buffer; - - /** - * The index of first valid character in the buffer. - *
- * 0 <= head < bufSize - */ - private int head; - - /** - * The index of last valid character in the buffer + 1. - *
- * 0 <= tail <= bufSize - */ - private int tail; - - /** - * The content encoding to use when reading headers. - */ - private String headerEncoding; - - /** - * The progress notifier, if any, or null. - */ - private final ProgressNotifier notifier; - - // ----------------------------------------------------------- Constructors - - /** - * Creates a new instance. - * - * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, - * ProgressNotifier)} - */ - @Deprecated - public MultipartStream() { - this(null, null, null); - } - - /** - *

Constructs a {@code MultipartStream} with a custom size buffer - * and no progress notifier. - * - *

Note that the buffer must be at least big enough to contain the - * boundary string, plus 4 characters for CR/LF and double dash, plus at - * least one byte of data. Too small a buffer size setting will degrade - * performance. - * - * @param input The {@code InputStream} to serve as a data source. - * @param boundary The token used for dividing the stream into - * {@code encapsulations}. - * @param bufSize The size of the buffer to be used, in bytes. - * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, - * ProgressNotifier)}. - */ - @Deprecated - public MultipartStream(final InputStream input, final byte[] boundary, final int bufSize) { - this(input, boundary, bufSize, null); - } - - /** - *

Constructs a {@code MultipartStream} with a custom size buffer. - * - *

Note that the buffer must be at least big enough to contain the - * boundary string, plus 4 characters for CR/LF and double dash, plus at - * least one byte of data. Too small a buffer size setting will degrade - * performance. - * - * @param input The {@code InputStream} to serve as a data source. - * @param boundary The token used for dividing the stream into - * {@code encapsulations}. - * @param bufSize The size of the buffer to be used, in bytes. - * @param pNotifier The notifier, which is used for calling the - * progress listener, if any. - * @throws IllegalArgumentException If the buffer size is too small - * @since 1.3.1 - */ - public MultipartStream(final InputStream input, - final byte[] boundary, - final int bufSize, - final ProgressNotifier pNotifier) { - - if (boundary == null) { - throw new IllegalArgumentException("boundary may not be null"); - } - // We prepend CR/LF to the boundary to chop trailing CR/LF from - // body-data tokens. - this.boundaryLength = boundary.length + BOUNDARY_PREFIX.length; - if (bufSize < this.boundaryLength + 1) { - throw new IllegalArgumentException( - "The buffer size specified for the MultipartStream is too small"); - } - - this.input = input; - this.bufSize = Math.max(bufSize, boundaryLength * 2); - this.buffer = new byte[this.bufSize]; - this.notifier = pNotifier; - - this.boundary = new byte[this.boundaryLength]; - this.boundaryTable = new int[this.boundaryLength + 1]; - this.keepRegion = this.boundary.length; - - System.arraycopy(BOUNDARY_PREFIX, 0, this.boundary, 0, - BOUNDARY_PREFIX.length); - System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, - boundary.length); - computeBoundaryTable(); - - head = 0; - tail = 0; - } - - /** - *

Constructs a {@code MultipartStream} with a default size buffer. - * - * @param input The {@code InputStream} to serve as a data source. - * @param boundary The token used for dividing the stream into - * {@code encapsulations}. - * @param pNotifier An object for calling the progress listener, if any. - * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier) - */ - public MultipartStream(final InputStream input, - final byte[] boundary, - final ProgressNotifier pNotifier) { - this(input, boundary, DEFAULT_BUFSIZE, pNotifier); - } - - /** - *

Constructs a {@code MultipartStream} with a default size buffer. - * - * @param input The {@code InputStream} to serve as a data source. - * @param boundary The token used for dividing the stream into - * {@code encapsulations}. - * @deprecated 1.2.1 Use {@link #MultipartStream(InputStream, byte[], int, - * ProgressNotifier)}. - */ - @Deprecated - public MultipartStream(final InputStream input, - final byte[] boundary) { - this(input, boundary, DEFAULT_BUFSIZE, null); - } - - // --------------------------------------------------------- Public methods - - /** - * Retrieves the character encoding used when reading the headers of an - * individual part. When not specified, or {@code null}, the platform - * default encoding is used. - * - * @return The encoding used to read part headers. - */ - public String getHeaderEncoding() { - return headerEncoding; - } - - /** - * Specifies the character encoding to be used when reading the headers of - * individual parts. When not specified, or {@code null}, the platform - * default encoding is used. - * - * @param encoding The encoding used to read part headers. - */ - public void setHeaderEncoding(final String encoding) { - headerEncoding = encoding; - } - - /** - * Reads a byte from the {@code buffer}, and refills it as - * necessary. - * - * @return The next byte from the input stream. - * @throws IOException if there is no more data available. - */ - public byte readByte() throws IOException { - // Buffer depleted ? - if (head == tail) { - head = 0; - // Refill. - tail = input.read(buffer, head, bufSize); - if (tail == -1) { - // No more data available. - throw new IOException("No more data is available"); - } - if (notifier != null) { - notifier.noteBytesRead(tail); - } - } - return buffer[head++]; - } - - /** - * Skips a {@code boundary} token, and checks whether more - * {@code encapsulations} are contained in the stream. - * - * @return {@code true} if there are more encapsulations in - * this stream; {@code false} otherwise. - * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits - * @throws MalformedStreamException if the stream ends unexpectedly or - * fails to follow required syntax. - */ - public boolean readBoundary() - throws FileUploadIOException, MalformedStreamException { - final byte[] marker = new byte[2]; - final boolean nextChunk; - - head += boundaryLength; - try { - marker[0] = readByte(); - if (marker[0] == LF) { - // Work around IE5 Mac bug with input type=image. - // Because the boundary delimiter, not including the trailing - // CRLF, must not appear within any file (RFC 2046, section - // 5.1.1), we know the missing CR is due to a buggy browser - // rather than a file containing something similar to a - // boundary. - return true; - } - - marker[1] = readByte(); - if (arrayequals(marker, STREAM_TERMINATOR, 2)) { - nextChunk = false; - } else if (arrayequals(marker, FIELD_SEPARATOR, 2)) { - nextChunk = true; - } else { - throw new MalformedStreamException( - "Unexpected characters follow a boundary"); - } - } catch (final FileUploadIOException e) { - // wraps a SizeException, re-throw as it will be unwrapped later - throw e; - } catch (final IOException e) { - throw new MalformedStreamException("Stream ended unexpectedly"); - } - return nextChunk; - } - - /** - *

Changes the boundary token used for partitioning the stream. - * - *

This method allows single pass processing of nested multipart - * streams. - * - *

The boundary token of the nested stream is {@code required} - * to be of the same length as the boundary token in parent stream. - * - *

Restoring the parent stream boundary token after processing of a - * nested stream is left to the application. - * - * @param boundary The boundary to be used for parsing of the nested - * stream. - * @throws IllegalBoundaryException if the {@code boundary} - * has a different length than the one - * being currently parsed. - */ - public void setBoundary(final byte[] boundary) - throws IllegalBoundaryException { - if (boundary.length != boundaryLength - BOUNDARY_PREFIX.length) { - throw new IllegalBoundaryException( - "The length of a boundary token cannot be changed"); - } - System.arraycopy(boundary, 0, this.boundary, BOUNDARY_PREFIX.length, - boundary.length); - computeBoundaryTable(); - } - - /** - * Compute the table used for Knuth-Morris-Pratt search algorithm. - */ - private void computeBoundaryTable() { - int position = 2; - int candidate = 0; - - boundaryTable[0] = -1; - boundaryTable[1] = 0; - - while (position <= boundaryLength) { - if (boundary[position - 1] == boundary[candidate]) { - boundaryTable[position] = candidate + 1; - candidate++; - position++; - } else if (candidate > 0) { - candidate = boundaryTable[candidate]; - } else { - boundaryTable[position] = 0; - position++; - } - } - } - - /** - *

Reads the {@code header-part} of the current - * {@code encapsulation}. - * - *

Headers are returned verbatim to the input stream, including the - * trailing {@code CRLF} marker. Parsing is left to the - * application. - * - *

TODO allow limiting maximum header size to - * protect against abuse. - * - * @return The {@code header-part} of the current encapsulation. - * @throws FileUploadIOException if the bytes read from the stream exceeded the size limits. - * @throws MalformedStreamException if the stream ends unexpectedly. - */ - public String readHeaders() throws FileUploadIOException, MalformedStreamException { - int i = 0; - byte b; - // to support multi-byte characters - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - int size = 0; - while (i < HEADER_SEPARATOR.length) { - try { - b = readByte(); - } catch (final FileUploadIOException e) { - // wraps a SizeException, re-throw as it will be unwrapped later - throw e; - } catch (final IOException e) { - throw new MalformedStreamException("Stream ended unexpectedly"); - } - if (++size > HEADER_PART_SIZE_MAX) { - throw new MalformedStreamException( - format("Header section has more than %s bytes (maybe it is not properly terminated)", - HEADER_PART_SIZE_MAX)); - } - if (b == HEADER_SEPARATOR[i]) { - i++; - } else { - i = 0; - } - baos.write(b); - } - - String headers; - if (headerEncoding != null) { - try { - headers = baos.toString(headerEncoding); - } catch (final UnsupportedEncodingException e) { - // Fall back to platform default if specified encoding is not - // supported. - headers = baos.toString(); - } - } else { - headers = baos.toString(); - } - - return headers; - } - - /** - *

Reads {@code body-data} from the current - * {@code encapsulation} and writes its contents into the - * output {@code Stream}. - * - *

Arbitrary large amounts of data can be processed by this - * method using a constant size buffer. (see {@link - * #MultipartStream(InputStream, byte[], int, - * ProgressNotifier) constructor}). - * - * @param output The {@code Stream} to write data into. May - * be null, in which case this method is equivalent - * to {@link #discardBodyData()}. - * @return the amount of data written. - * @throws MalformedStreamException if the stream ends unexpectedly. - * @throws IOException if an i/o error occurs. - */ - public int readBodyData(final OutputStream output) - throws MalformedStreamException, IOException { - return (int) Streams.copy(newInputStream(), output, false); // N.B. Streams.copy closes the input stream - } - - /** - * Creates a new {@link ItemInputStream}. - * - * @return A new instance of {@link ItemInputStream}. - */ - public ItemInputStream newInputStream() { - return new ItemInputStream(); - } - - /** - *

Reads {@code body-data} from the current - * {@code encapsulation} and discards it. - * - *

Use this method to skip encapsulations you don't need or don't - * understand. - * - * @return The amount of data discarded. - * @throws MalformedStreamException if the stream ends unexpectedly. - * @throws IOException if an i/o error occurs. - */ - public int discardBodyData() throws MalformedStreamException, IOException { - return readBodyData(null); - } - - /** - * Finds the beginning of the first {@code encapsulation}. - * - * @return {@code true} if an {@code encapsulation} was found in - * the stream. - * @throws IOException if an i/o error occurs. - */ - public boolean skipPreamble() throws IOException { - // First delimiter may be not preceded with a CRLF. - System.arraycopy(boundary, 2, boundary, 0, boundary.length - 2); - boundaryLength = boundary.length - 2; - computeBoundaryTable(); - try { - // Discard all data up to the delimiter. - discardBodyData(); - - // Read boundary - if succeeded, the stream contains an - // encapsulation. - return readBoundary(); - } catch (final MalformedStreamException e) { - return false; - } finally { - // Restore delimiter. - System.arraycopy(boundary, 0, boundary, 2, boundary.length - 2); - boundaryLength = boundary.length; - boundary[0] = CR; - boundary[1] = LF; - computeBoundaryTable(); - } - } - - /** - * Compares {@code count} first bytes in the arrays - * {@code a} and {@code b}. - * - * @param a The first array to compare. - * @param b The second array to compare. - * @param count How many bytes should be compared. - * @return {@code true} if {@code count} first bytes in arrays - * {@code a} and {@code b} are equal. - */ - public static boolean arrayequals(final byte[] a, - final byte[] b, - final int count) { - for (int i = 0; i < count; i++) { - if (a[i] != b[i]) { - return false; - } - } - return true; - } - - /** - * Searches for a byte of specified value in the {@code buffer}, - * starting at the specified {@code position}. - * - * @param value The value to find. - * @param pos The starting position for searching. - * @return The position of byte found, counting from beginning of the - * {@code buffer}, or {@code -1} if not found. - */ - protected int findByte(final byte value, - final int pos) { - for (int i = pos; i < tail; i++) { - if (buffer[i] == value) { - return i; - } - } - - return -1; - } - - /** - * Searches for the {@code boundary} in the {@code buffer} - * region delimited by {@code head} and {@code tail}. - * - * @return The position of the boundary found, counting from the - * beginning of the {@code buffer}, or {@code -1} if - * not found. - */ - protected int findSeparator() { - - int bufferPos = this.head; - int tablePos = 0; - - while (bufferPos < this.tail) { - while (tablePos >= 0 && buffer[bufferPos] != boundary[tablePos]) { - tablePos = boundaryTable[tablePos]; - } - bufferPos++; - tablePos++; - if (tablePos == boundaryLength) { - return bufferPos - boundaryLength; - } - } - return -1; - } - - /** - * Thrown to indicate that the input stream fails to follow the - * required syntax. - */ - public static class MalformedStreamException extends IOException { - - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = 6466926458059796677L; - - /** - * Constructs a {@code MalformedStreamException} with no - * detail message. - */ - public MalformedStreamException() { - } - - /** - * Constructs an {@code MalformedStreamException} with - * the specified detail message. - * - * @param message The detail message. - */ - public MalformedStreamException(final String message) { - super(message); - } - - } - - /** - * Thrown upon attempt of setting an invalid boundary token. - */ - public static class IllegalBoundaryException extends IOException { - - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = -161533165102632918L; - - /** - * Constructs an {@code IllegalBoundaryException} with no - * detail message. - */ - public IllegalBoundaryException() { - } - - /** - * Constructs an {@code IllegalBoundaryException} with - * the specified detail message. - * - * @param message The detail message. - */ - public IllegalBoundaryException(final String message) { - super(message); - } - - } - - /** - * An {@link InputStream} for reading an items contents. - */ - public class ItemInputStream extends InputStream implements Closeable { - - /** - * The number of bytes, which have been read so far. - */ - private long total; - - /** - * The number of bytes, which must be hold, because - * they might be a part of the boundary. - */ - private int pad; - - /** - * The current offset in the buffer. - */ - private int pos; - - /** - * Whether the stream is already closed. - */ - private boolean closed; - - /** - * Creates a new instance. - */ - ItemInputStream() { - findSeparator(); - } - - /** - * Called for finding the separator. - */ - private void findSeparator() { - pos = MultipartStream.this.findSeparator(); - if (pos == -1) { - if (tail - head > keepRegion) { - pad = keepRegion; - } else { - pad = tail - head; - } - } - } - - /** - * Returns the number of bytes, which have been read - * by the stream. - * - * @return Number of bytes, which have been read so far. - */ - public long getBytesRead() { - return total; - } - - /** - * Returns the number of bytes, which are currently - * available, without blocking. - * - * @return Number of bytes in the buffer. - * @throws IOException An I/O error occurs. - */ - @Override - public int available() throws IOException { - if (pos == -1) { - return tail - head - pad; - } - return pos - head; - } - - /** - * Offset when converting negative bytes to integers. - */ - private static final int BYTE_POSITIVE_OFFSET = 256; - - /** - * Returns the next byte in the stream. - * - * @return The next byte in the stream, as a non-negative - * integer, or -1 for EOF. - * @throws IOException An I/O error occurred. - */ - @Override - public int read() throws IOException { - if (closed) { - throw new FileItemStream.ItemSkippedException(); - } - if (available() == 0 && makeAvailable() == 0) { - return -1; - } - ++total; - final int b = buffer[head++]; - if (b >= 0) { - return b; - } - return b + BYTE_POSITIVE_OFFSET; - } - - /** - * Reads bytes into the given buffer. - * - * @param b The destination buffer, where to write to. - * @param off Offset of the first byte in the buffer. - * @param len Maximum number of bytes to read. - * @return Number of bytes, which have been actually read, - * or -1 for EOF. - * @throws IOException An I/O error occurred. - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - if (closed) { - throw new FileItemStream.ItemSkippedException(); - } - if (len == 0) { - return 0; - } - int res = available(); - if (res == 0) { - res = makeAvailable(); - if (res == 0) { - return -1; - } - } - res = Math.min(res, len); - System.arraycopy(buffer, head, b, off, res); - head += res; - total += res; - return res; - } - - /** - * Closes the input stream. - * - * @throws IOException An I/O error occurred. - */ - @Override - public void close() throws IOException { - close(false); - } - - /** - * Closes the input stream. - * - * @param pCloseUnderlying Whether to close the underlying stream - * (hard close) - * @throws IOException An I/O error occurred. - */ - public void close(final boolean pCloseUnderlying) throws IOException { - if (closed) { - return; - } - if (pCloseUnderlying) { - closed = true; - input.close(); - } else { - for (; ; ) { - int av = available(); - if (av == 0) { - av = makeAvailable(); - if (av == 0) { - break; - } - } - skip(av); - } - } - closed = true; - } - - /** - * Skips the given number of bytes. - * - * @param bytes Number of bytes to skip. - * @return The number of bytes, which have actually been - * skipped. - * @throws IOException An I/O error occurred. - */ - @Override - public long skip(final long bytes) throws IOException { - if (closed) { - throw new FileItemStream.ItemSkippedException(); - } - int av = available(); - if (av == 0) { - av = makeAvailable(); - if (av == 0) { - return 0; - } - } - final long res = Math.min(av, bytes); - head += res; - return res; - } - - /** - * Attempts to read more data. - * - * @return Number of available bytes - * @throws IOException An I/O error occurred. - */ - private int makeAvailable() throws IOException { - if (pos != -1) { - return 0; - } - - // Move the data to the beginning of the buffer. - total += tail - head - pad; - System.arraycopy(buffer, tail - pad, buffer, 0, pad); - - // Refill buffer with new data. - head = 0; - tail = pad; - - for (; ; ) { - final int bytesRead = input.read(buffer, tail, bufSize - tail); - if (bytesRead == -1) { - // The last pad amount is left in the buffer. - // Boundary can't be in there so signal an error - // condition. - final String msg = "Stream ended unexpectedly"; - throw new MalformedStreamException(msg); - } - if (notifier != null) { - notifier.noteBytesRead(bytesRead); - } - tail += bytesRead; - - findSeparator(); - final int av = available(); - - if (av > 0 || pos != -1) { - return av; - } - } - } - - /** - * Returns, whether the stream is closed. - * - * @return True, if the stream is closed, otherwise false. - */ - @Override - public boolean isClosed() { - return closed; - } - - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/ParameterParser.java b/client/src/test/java/org/apache/commons/fileupload2/ParameterParser.java deleted file mode 100644 index bd00a9a11b..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/ParameterParser.java +++ /dev/null @@ -1,333 +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.commons.fileupload2; - -import org.apache.commons.fileupload2.util.mime.MimeUtility; -import org.apache.commons.fileupload2.util.mime.RFC2231Utility; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -/** - * A simple parser intended to parse sequences of name/value pairs. - *

- * Parameter values are expected to be enclosed in quotes if they - * contain unsafe characters, such as '=' characters or separators. - * Parameter values are optional and can be omitted. - * - *

- * {@code param1 = value; param2 = "anything goes; really"; param3} - *

- */ -public class ParameterParser { - - /** - * String to be parsed. - */ - private char[] chars = null; - - /** - * Current position in the string. - */ - private int pos = 0; - - /** - * Maximum position in the string. - */ - private int len = 0; - - /** - * Start of a token. - */ - private int i1 = 0; - - /** - * End of a token. - */ - private int i2 = 0; - - /** - * Whether names stored in the map should be converted to lower case. - */ - private boolean lowerCaseNames = false; - - /** - * Default ParameterParser constructor. - */ - public ParameterParser() { - } - - /** - * Are there any characters left to parse? - * - * @return {@code true} if there are unparsed characters, - * {@code false} otherwise. - */ - private boolean hasChar() { - return this.pos < this.len; - } - - /** - * A helper method to process the parsed token. This method removes - * leading and trailing blanks as well as enclosing quotation marks, - * when necessary. - * - * @param quoted {@code true} if quotation marks are expected, - * {@code false} otherwise. - * @return the token - */ - private String getToken(final boolean quoted) { - // Trim leading white spaces - while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) { - i1++; - } - // Trim trailing white spaces - while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) { - i2--; - } - // Strip away quotation marks if necessary - if (quoted - && ((i2 - i1) >= 2) - && (chars[i1] == '"') - && (chars[i2 - 1] == '"')) { - i1++; - i2--; - } - String result = null; - if (i2 > i1) { - result = new String(chars, i1, i2 - i1); - } - return result; - } - - /** - * Tests if the given character is present in the array of characters. - * - * @param ch the character to test for presence in the array of characters - * @param charray the array of characters to test against - * @return {@code true} if the character is present in the array of - * characters, {@code false} otherwise. - */ - private boolean isOneOf(final char ch, final char[] charray) { - boolean result = false; - for (final char element : charray) { - if (ch == element) { - result = true; - break; - } - } - return result; - } - - /** - * Parses out a token until any of the given terminators - * is encountered. - * - * @param terminators the array of terminating characters. Any of these - * characters when encountered signify the end of the token - * @return the token - */ - private String parseToken(final char[] terminators) { - char ch; - i1 = pos; - i2 = pos; - while (hasChar()) { - ch = chars[pos]; - if (isOneOf(ch, terminators)) { - break; - } - i2++; - pos++; - } - return getToken(false); - } - - /** - * Parses out a token until any of the given terminators - * is encountered outside the quotation marks. - * - * @param terminators the array of terminating characters. Any of these - * characters when encountered outside the quotation marks signify the end - * of the token - * @return the token - */ - private String parseQuotedToken(final char[] terminators) { - char ch; - i1 = pos; - i2 = pos; - boolean quoted = false; - boolean charEscaped = false; - while (hasChar()) { - ch = chars[pos]; - if (!quoted && isOneOf(ch, terminators)) { - break; - } - if (!charEscaped && ch == '"') { - quoted = !quoted; - } - charEscaped = (!charEscaped && ch == '\\'); - i2++; - pos++; - - } - return getToken(true); - } - - /** - * Returns {@code true} if parameter names are to be converted to lower - * case when name/value pairs are parsed. - * - * @return {@code true} if parameter names are to be - * converted to lower case when name/value pairs are parsed. - * Otherwise returns {@code false} - */ - public boolean isLowerCaseNames() { - return this.lowerCaseNames; - } - - /** - * Sets the flag if parameter names are to be converted to lower case when - * name/value pairs are parsed. - * - * @param b {@code true} if parameter names are to be - * converted to lower case when name/value pairs are parsed. - * {@code false} otherwise. - */ - public void setLowerCaseNames(final boolean b) { - this.lowerCaseNames = b; - } - - /** - * Extracts a map of name/value pairs from the given string. Names are - * expected to be unique. Multiple separators may be specified and - * the earliest found in the input string is used. - * - * @param str the string that contains a sequence of name/value pairs - * @param separators the name/value pairs separators - * @return a map of name/value pairs - */ - public Map parse(final String str, final char[] separators) { - if (separators == null || separators.length == 0) { - return new HashMap<>(); - } - char separator = separators[0]; - if (str != null) { - int idx = str.length(); - for (final char separator2 : separators) { - final int tmp = str.indexOf(separator2); - if (tmp != -1 && tmp < idx) { - idx = tmp; - separator = separator2; - } - } - } - return parse(str, separator); - } - - /** - * Extracts a map of name/value pairs from the given string. Names are - * expected to be unique. - * - * @param str the string that contains a sequence of name/value pairs - * @param separator the name/value pairs separator - * @return a map of name/value pairs - */ - public Map parse(final String str, final char separator) { - if (str == null) { - return new HashMap<>(); - } - return parse(str.toCharArray(), separator); - } - - /** - * Extracts a map of name/value pairs from the given array of - * characters. Names are expected to be unique. - * - * @param charArray the array of characters that contains a sequence of - * name/value pairs - * @param separator the name/value pairs separator - * @return a map of name/value pairs - */ - public Map parse(final char[] charArray, final char separator) { - if (charArray == null) { - return new HashMap<>(); - } - return parse(charArray, 0, charArray.length, separator); - } - - /** - * Extracts a map of name/value pairs from the given array of - * characters. Names are expected to be unique. - * - * @param charArray the array of characters that contains a sequence of - * name/value pairs - * @param offset - the initial offset. - * @param length - the length. - * @param separator the name/value pairs separator - * @return a map of name/value pairs - */ - public Map parse( - final char[] charArray, - final int offset, - final int length, - final char separator) { - - if (charArray == null) { - return new HashMap<>(); - } - final HashMap params = new HashMap<>(); - this.chars = charArray.clone(); - this.pos = offset; - this.len = length; - - String paramName; - String paramValue; - while (hasChar()) { - paramName = parseToken(new char[]{ - '=', separator}); - paramValue = null; - if (hasChar() && (charArray[pos] == '=')) { - pos++; // skip '=' - paramValue = parseQuotedToken(new char[]{ - separator}); - - if (paramValue != null) { - try { - paramValue = RFC2231Utility.hasEncodedValue(paramName) ? RFC2231Utility.decodeText(paramValue) - : MimeUtility.decodeText(paramValue); - } catch (final UnsupportedEncodingException e) { - // let's keep the original value in this case - } - } - } - if (hasChar() && (charArray[pos] == separator)) { - pos++; // skip separator - } - if ((paramName != null) && !paramName.isEmpty()) { - paramName = RFC2231Utility.stripDelimiter(paramName); - if (this.lowerCaseNames) { - paramName = paramName.toLowerCase(Locale.ENGLISH); - } - params.put(paramName, paramValue); - } - } - return params; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/ProgressListener.java b/client/src/test/java/org/apache/commons/fileupload2/ProgressListener.java deleted file mode 100644 index 7f33ec8f28..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/ProgressListener.java +++ /dev/null @@ -1,37 +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.commons.fileupload2; - -/** - * The {@link ProgressListener} may be used to display a progress bar - * or do stuff like that. - */ -public interface ProgressListener { - - /** - * Updates the listeners status information. - * - * @param pBytesRead The total number of bytes, which have been read - * so far. - * @param pContentLength The total number of bytes, which are being - * read. May be -1, if this number is unknown. - * @param pItems The number of the field, which is currently being - * read. (0 = no item so far, 1 = first item is being read, ...) - */ - void update(long pBytesRead, long pContentLength, int pItems); - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/RequestContext.java b/client/src/test/java/org/apache/commons/fileupload2/RequestContext.java deleted file mode 100644 index 8cb590faff..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/RequestContext.java +++ /dev/null @@ -1,62 +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.commons.fileupload2; - -import java.io.IOException; -import java.io.InputStream; - -/** - *

Abstracts access to the request information needed for file uploads. This - * interface should be implemented for each type of request that may be - * handled by FileUpload, such as servlets and portlets.

- * - * @since 1.1 - */ -public interface RequestContext { - - /** - * Retrieve the character encoding for the request. - * - * @return The character encoding for the request. - */ - String getCharacterEncoding(); - - /** - * Retrieve the content type of the request. - * - * @return The content type of the request. - */ - String getContentType(); - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @deprecated 1.3 Use {@link UploadContext#contentLength()} instead - */ - @Deprecated - int getContentLength(); - - /** - * Retrieve the input stream for the request. - * - * @return The input stream for the request. - * @throws IOException if a problem occurs. - */ - InputStream getInputStream() throws IOException; - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/UploadContext.java b/client/src/test/java/org/apache/commons/fileupload2/UploadContext.java deleted file mode 100644 index 181ac7b1c9..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/UploadContext.java +++ /dev/null @@ -1,39 +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.commons.fileupload2; - -/** - * Enhanced access to the request information needed for file uploads, - * which fixes the Content Length data access in {@link RequestContext}. - *

- * The reason of introducing this new interface is just for backward compatibility - * and it might vanish for a refactored 2.x version moving the new method into - * RequestContext again. - * - * @since 1.3 - */ -public interface UploadContext extends RequestContext { - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @since 1.3 - */ - long contentLength(); - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItem.java b/client/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItem.java deleted file mode 100644 index 1f68478c3e..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItem.java +++ /dev/null @@ -1,615 +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.commons.fileupload2.disk; - -import org.apache.commons.fileupload2.FileItem; -import org.apache.commons.fileupload2.FileItemHeaders; -import org.apache.commons.fileupload2.FileUploadException; -import org.apache.commons.fileupload2.ParameterParser; -import org.apache.commons.fileupload2.util.Streams; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.DeferredFileOutputStream; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.io.UnsupportedEncodingException; -import java.nio.file.Files; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - -import static java.lang.String.format; - -/** - *

The default implementation of the - * {@link FileItem FileItem} interface. - * - *

After retrieving an instance of this class from a {@link - * DiskFileItemFactory} instance (see - * {@link org.apache.commons.fileupload2.servlet.ServletFileUpload - * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may - * either request all contents of file at once using {@link #get()} or - * request an {@link InputStream InputStream} with - * {@link #getInputStream()} and process the file without attempting to load - * it into memory, which may come handy with large files. - * - *

Temporary files, which are created for file items, should be - * deleted later on. The best way to do this is using a - * {@link org.apache.commons.io.FileCleaningTracker}, which you can set on the - * {@link DiskFileItemFactory}. However, if you do use such a tracker, - * then you must consider the following: Temporary files are automatically - * deleted as soon as they are no longer needed. (More precisely, when the - * corresponding instance of {@link File} is garbage collected.) - * This is done by the so-called reaper thread, which is started and stopped - * automatically by the {@link org.apache.commons.io.FileCleaningTracker} when - * there are files to be tracked. - * 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.

- * - * @since 1.1 - */ -public class DiskFileItem - implements FileItem { - - // ----------------------------------------------------- Manifest constants - - /** - * 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 = - UUID.randomUUID().toString().replace('-', '_'); - - /** - * Counter used in unique identifier generation. - */ - private static final AtomicInteger COUNTER = new AtomicInteger(0); - - /** - * The name of the form field as provided by the browser. - */ - private String fieldName; - - /** - * The content type passed by the browser, or {@code null} if - * not defined. - */ - private final String contentType; - - /** - * Whether or not this item is a simple form field. - */ - private boolean isFormField; - - /** - * The original file name in the user's file system. - */ - private final 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 final int sizeThreshold; - - /** - * The directory in which uploaded files will be stored, if stored on disk. - */ - private final 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; - - /** - * The file items headers. - */ - private FileItemHeaders headers; - - /** - * Default content charset to be used when no explicit charset - * parameter is provided by the sender. - */ - private String defaultCharset = DEFAULT_CHARSET; - - // ----------------------------------------------------------- Constructors - - /** - * Constructs a new {@code DiskFileItem} instance. - * - * @param fieldName The name of the form field. - * @param contentType The content type passed by the browser or - * {@code 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 file name in the user's file system, or - * {@code 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(final String fieldName, - final String contentType, final boolean isFormField, final String fileName, - final int sizeThreshold, final 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 InputStream InputStream} that can be - * used to retrieve the contents of the file. - * - * @return An {@link InputStream InputStream} that can be - * used to retrieve the contents of the file. - * @throws IOException if an error occurs. - */ - @Override - public InputStream getInputStream() - throws IOException { - if (!isInMemory()) { - return Files.newInputStream(dfos.getFile().toPath()); - } - - if (cachedContent == null) { - cachedContent = dfos.getData(); - } - return new ByteArrayInputStream(cachedContent); - } - - /** - * Returns the content type passed by the agent or {@code null} if - * not defined. - * - * @return The content type passed by the agent or {@code null} if - * not defined. - */ - @Override - public String getContentType() { - return contentType; - } - - /** - * Returns the content charset passed by the agent or {@code null} if - * not defined. - * - * @return The content charset passed by the agent or {@code null} if - * not defined. - */ - public String getCharSet() { - final ParameterParser parser = new ParameterParser(); - parser.setLowerCaseNames(true); - // Parameter parser can handle null input - final Map params = parser.parse(getContentType(), ';'); - return params.get("charset"); - } - - /** - * Returns the original file name in the client's file system. - * - * @return The original file name in the client's file system. - * @throws org.apache.commons.fileupload2.InvalidFileNameException The file name contains a NUL character, - * which might be an indicator of a security attack. If you intend to - * use the file name anyways, catch the exception and use - * {@link org.apache.commons.fileupload2.InvalidFileNameException#getName()}. - */ - @Override - public String getName() { - return Streams.checkFileName(fileName); - } - - // ------------------------------------------------------- FileItem methods - - /** - * Provides a hint as to whether or not the file contents will be read - * from memory. - * - * @return {@code true} if the file contents will be read - * from memory; {@code false} otherwise. - */ - @Override - 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. - */ - @Override - public long getSize() { - if (size >= 0) { - return size; - } - if (cachedContent != null) { - return cachedContent.length; - } - if (dfos.isInMemory()) { - return dfos.getData().length; - } - 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 - * or {@code null} if the data cannot be read - * @throws UncheckedIOException if an I/O error occurs - */ - @Override - public byte[] get() throws UncheckedIOException { - if (isInMemory()) { - if (cachedContent == null && dfos != null) { - cachedContent = dfos.getData(); - } - return cachedContent != null ? cachedContent.clone() : new byte[0]; - } - - final byte[] fileData = new byte[(int) getSize()]; - - try (InputStream fis = Files.newInputStream(dfos.getFile().toPath())) { - IOUtils.readFully(fis, fileData); - } catch (final IOException e) { - throw new UncheckedIOException(e); - } - 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. - */ - @Override - public String getString(final String charset) - throws UnsupportedEncodingException, IOException { - 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. - * - * TODO Consider making this method throw UnsupportedEncodingException. - * - * @return The contents of the file, as a string. - */ - @Override - public String getString() { - try { - final byte[] rawData = get(); - String charset = getCharSet(); - if (charset == null) { - charset = defaultCharset; - } - return new String(rawData, charset); - } catch (final IOException e) { - return ""; - } - } - - /** - * 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 {@code File} into which the uploaded item should - * be stored. - * @throws Exception if an error occurs. - */ - @Override - public void write(final File file) throws Exception { - if (isInMemory()) { - try (OutputStream fout = Files.newOutputStream(file.toPath())) { - fout.write(get()); - } catch (final IOException e) { - throw new IOException("Unexpected output data"); - } - } else { - final File outputFile = getStoreLocation(); - if (outputFile == null) { - /* - * For whatever reason we cannot write the - * file to disk. - */ - throw new FileUploadException( - "Cannot write uploaded file to disk!"); - } - // 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 (file.exists() && !file.delete()) { - throw new FileUploadException( - "Cannot write uploaded file to disk!"); - } - FileUtils.moveFile(outputFile, file); - } - } - - /** - * Deletes the underlying storage for a file item, including deleting any associated temporary disk file. - * This method can be used to ensure that this is done at an earlier time, thus preserving system resources. - */ - @Override - public void delete() { - cachedContent = null; - final File outputFile = getStoreLocation(); - if (outputFile != null && !isInMemory() && outputFile.exists()) { - if (!outputFile.delete()) { - final String desc = "Cannot delete " + outputFile.toString(); - throw new UncheckedIOException(desc, new IOException(desc)); - } - } - } - - /** - * Returns the name of the field in the multipart form corresponding to - * this file item. - * - * @return The name of the form field. - * @see #setFieldName(String) - */ - @Override - 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() - */ - @Override - public void setFieldName(final String fieldName) { - this.fieldName = fieldName; - } - - /** - * Determines whether or not a {@code FileItem} instance represents - * a simple form field. - * - * @return {@code true} if the instance represents a simple form - * field; {@code false} if it represents an uploaded file. - * @see #setFormField(boolean) - */ - @Override - public boolean isFormField() { - return isFormField; - } - - /** - * Specifies whether or not a {@code FileItem} instance represents - * a simple form field. - * - * @param state {@code true} if the instance represents a simple form - * field; {@code false} if it represents an uploaded file. - * @see #isFormField() - */ - @Override - public void setFormField(final boolean state) { - isFormField = state; - } - - /** - * Returns an {@link OutputStream OutputStream} that can - * be used for storing the contents of the file. - * - * @return An {@link OutputStream OutputStream} that can be used - * for storing the contents of the file. - */ - @Override - public OutputStream getOutputStream() { - if (dfos == null) { - final File outputFile = getTempFile(); - dfos = new DeferredFileOutputStream(sizeThreshold, outputFile); - } - return dfos; - } - - // --------------------------------------------------------- Public methods - - /** - * Returns the {@link File} object for the {@code FileItem}'s - * data's temporary location on the disk. Note that for - * {@code FileItem}s that have their data stored in memory, - * this method will return {@code null}. When handling large - * files, you can use {@link File#renameTo(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 {@code null} if the data is stored in - * memory. - */ - public File getStoreLocation() { - if (dfos == null) { - return null; - } - if (isInMemory()) { - return null; - } - return dfos.getFile(); - } - - // ------------------------------------------------------ Protected methods - - /** - * Creates and returns a {@link 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 {@code FileItem} instance; - * the file will be deleted when the instance is garbage collected. - *

- * Note: Subclasses that override this method must ensure that they return the - * same File each time. - * - * @return The {@link 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")); - } - - final String tempFileName = format("upload_%s_%s.tmp", UID, getUniqueId()); - - 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 appearance. - * - * @return A String with the non-random looking instance identifier. - */ - private static String getUniqueId() { - final int limit = 100000000; - final int current = COUNTER.getAndIncrement(); - 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 format("name=%s, StoreLocation=%s, size=%s bytes, isFormField=%s, FieldName=%s", - getName(), getStoreLocation(), getSize(), - isFormField(), getFieldName()); - } - - /** - * Returns the file item headers. - * - * @return The file items headers. - */ - @Override - public FileItemHeaders getHeaders() { - return headers; - } - - /** - * Sets the file item headers. - * - * @param pHeaders The file items headers. - */ - @Override - public void setHeaders(final FileItemHeaders pHeaders) { - headers = pHeaders; - } - - /** - * Returns the default charset for use when no explicit charset - * parameter is provided by the sender. - * - * @return the default charset - */ - public String getDefaultCharset() { - return defaultCharset; - } - - /** - * Sets the default charset for use when no explicit charset - * parameter is provided by the sender. - * - * @param charset the default charset - */ - public void setDefaultCharset(final String charset) { - defaultCharset = charset; - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java b/client/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java deleted file mode 100644 index 56d8154dee..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/disk/DiskFileItemFactory.java +++ /dev/null @@ -1,244 +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.commons.fileupload2.disk; - -import org.apache.commons.fileupload2.FileItem; -import org.apache.commons.fileupload2.FileItemFactory; -import org.apache.commons.io.FileCleaningTracker; - -import java.io.File; - -/** - *

The default {@link FileItemFactory} - * implementation. This implementation creates - * {@link 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 - * {@code System.getProperty("java.io.tmpdir")}.
  • - *
- *

- * NOTE: Files are created in the system default temp directory with - * predictable names. This means that a local attacker with write access to that - * directory can perform a TOUTOC attack to replace any uploaded file with a - * file of the attackers choice. The implications of this will depend on how the - * uploaded file is used but could be significant. When using this - * implementation in an environment with local, untrusted users, - * {@link #setRepository(File)} MUST be used to configure a repository location - * that is not publicly writable. In a Servlet container the location identified - * by the ServletContext attribute {@code javax.servlet.context.tempdir} - * may be used. - *

- * - *

Temporary files, which are created for file items, should be - * deleted later on. The best way to do this is using a - * {@link FileCleaningTracker}, which you can set on the - * {@link DiskFileItemFactory}. However, if you do use such a tracker, - * then you must consider the following: Temporary files are automatically - * deleted as soon as they are no longer needed. (More precisely, when the - * corresponding instance of {@link File} is garbage collected.) - * This is done by the so-called reaper thread, which is started and stopped - * automatically by the {@link FileCleaningTracker} when there are files to be - * tracked. - * 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.

- * - * @since 1.1 - */ -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; - - /** - * Default content charset to be used when no explicit charset - * parameter is provided by the sender. - */ - private String defaultCharset = DiskFileItem.DEFAULT_CHARSET; - - // ----------------------------------------------------------- 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(final int sizeThreshold, final 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(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(final 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(final int sizeThreshold) { - this.sizeThreshold = sizeThreshold; - } - - // --------------------------------------------------------- Public Methods - - /** - * Create a new {@link 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 {@code true} if this is a plain form field; - * {@code 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. - */ - @Override - public FileItem createItem(final String fieldName, final String contentType, - final boolean isFormField, final String fileName) { - final DiskFileItem result = new DiskFileItem(fieldName, contentType, - isFormField, fileName, sizeThreshold, repository); - result.setDefaultCharset(defaultCharset); - final FileCleaningTracker tracker = getFileCleaningTracker(); - if (tracker != null) { - tracker.track(result.getTempFile(), result); - } - return result; - } - - /** - * Returns the tracker, which is responsible for deleting temporary - * files. - * - * @return An instance of {@link FileCleaningTracker}, or null - * (default), if temporary files aren't tracked. - */ - public FileCleaningTracker getFileCleaningTracker() { - return fileCleaningTracker; - } - - /** - * Sets 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, or null - * (default), to disable tracking. - */ - public void setFileCleaningTracker(final FileCleaningTracker pTracker) { - fileCleaningTracker = pTracker; - } - - /** - * Returns the default charset for use when no explicit charset - * parameter is provided by the sender. - * - * @return the default charset - */ - public String getDefaultCharset() { - return defaultCharset; - } - - /** - * Sets the default charset for use when no explicit charset - * parameter is provided by the sender. - * - * @param pCharset the default charset - */ - public void setDefaultCharset(final String pCharset) { - defaultCharset = pCharset; - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/disk/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/disk/package-info.java deleted file mode 100644 index 1d2caecb9b..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/disk/package-info.java +++ /dev/null @@ -1,54 +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. - */ - -/** - *

- * A disk-based implementation of the - * {@link org.apache.commons.fileupload2.FileItem FileItem} - * interface. This implementation retains smaller items in memory, while - * writing larger ones to disk. The threshold between these two is - * configurable, as is the location of files that are written to disk. - *

- *

- * In typical usage, an instance of - * {@link org.apache.commons.fileupload2.disk.DiskFileItemFactory DiskFileItemFactory} - * would be created, configured, and then passed to a - * {@link org.apache.commons.fileupload2.FileUpload FileUpload} - * implementation such as - * {@link org.apache.commons.fileupload2.servlet.ServletFileUpload ServletFileUpload} - * or - * {@link org.apache.commons.fileupload2.portlet.PortletFileUpload PortletFileUpload}. - *

- *

- * The following code fragment demonstrates this usage. - *

- *
- *        DiskFileItemFactory factory = new DiskFileItemFactory();
- *        // maximum size that will be stored in memory
- *        factory.setSizeThreshold(4096);
- *        // the location for saving data that is larger than getSizeThreshold()
- *        factory.setRepository(new File("/tmp"));
- *
- *        ServletFileUpload upload = new ServletFileUpload(factory);
- * 
- *

- * Please see the FileUpload - * User Guide - * for further details and examples of how to use this package. - *

- */ -package org.apache.commons.fileupload2.disk; diff --git a/client/src/test/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java b/client/src/test/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java deleted file mode 100644 index bd29bb87f9..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/impl/FileItemIteratorImpl.java +++ /dev/null @@ -1,362 +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.commons.fileupload2.impl; - -import org.apache.commons.fileupload2.FileItem; -import org.apache.commons.fileupload2.FileItemHeaders; -import org.apache.commons.fileupload2.FileItemIterator; -import org.apache.commons.fileupload2.FileItemStream; -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.FileUploadException; -import org.apache.commons.fileupload2.MultipartStream; -import org.apache.commons.fileupload2.ProgressListener; -import org.apache.commons.fileupload2.RequestContext; -import org.apache.commons.fileupload2.UploadContext; -import org.apache.commons.fileupload2.pub.FileUploadIOException; -import org.apache.commons.fileupload2.pub.InvalidContentTypeException; -import org.apache.commons.fileupload2.pub.SizeLimitExceededException; -import org.apache.commons.fileupload2.util.LimitedInputStream; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.NoSuchElementException; -import java.util.Objects; - -import static java.lang.String.format; - -/** - * The iterator, which is returned by - * {@link FileUploadBase#getItemIterator(RequestContext)}. - */ -public class FileItemIteratorImpl implements FileItemIterator { - /** - * The file uploads processing utility. - * - * @see FileUploadBase - */ - private final FileUploadBase fileUploadBase; - /** - * The request context. - * - * @see RequestContext - */ - private final RequestContext ctx; - /** - * The maximum allowed size of a complete request. - */ - private long sizeMax; - /** - * The maximum allowed size of a single uploaded file. - */ - private long fileSizeMax; - - - @Override - public long getSizeMax() { - return sizeMax; - } - - @Override - public void setSizeMax(final long sizeMax) { - this.sizeMax = sizeMax; - } - - @Override - public long getFileSizeMax() { - return fileSizeMax; - } - - @Override - public void setFileSizeMax(final long fileSizeMax) { - this.fileSizeMax = fileSizeMax; - } - - /** - * The multi part stream to process. - */ - private MultipartStream multiPartStream; - - /** - * The notifier, which used for triggering the - * {@link ProgressListener}. - */ - private MultipartStream.ProgressNotifier progressNotifier; - - /** - * The boundary, which separates the various parts. - */ - private byte[] multiPartBoundary; - - /** - * The item, which we currently process. - */ - private FileItemStreamImpl currentItem; - - /** - * The current items field name. - */ - private String currentFieldName; - - /** - * Whether we are currently skipping the preamble. - */ - private boolean skipPreamble; - - /** - * Whether the current item may still be read. - */ - private boolean itemValid; - - /** - * Whether we have seen the end of the file. - */ - private boolean eof; - - /** - * Creates a new instance. - * - * @param fileUploadBase Main processor. - * @param requestContext The request context. - * @throws FileUploadException An error occurred while - * parsing the request. - * @throws IOException An I/O error occurred. - */ - public FileItemIteratorImpl(final FileUploadBase fileUploadBase, final RequestContext requestContext) - throws FileUploadException, IOException { - this.fileUploadBase = fileUploadBase; - sizeMax = fileUploadBase.getSizeMax(); - fileSizeMax = fileUploadBase.getFileSizeMax(); - ctx = Objects.requireNonNull(requestContext, "requestContext"); - skipPreamble = true; - findNextItem(); - } - - protected void init(final FileUploadBase fileUploadBase, final RequestContext pRequestContext) - throws FileUploadException, IOException { - final String contentType = ctx.getContentType(); - if ((null == contentType) - || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) { - throw new InvalidContentTypeException( - format("the request doesn't contain a %s or %s stream, content type header is %s", - FileUploadBase.MULTIPART_FORM_DATA, FileUploadBase.MULTIPART_MIXED, contentType)); - } - final long contentLengthInt = ((UploadContext) ctx).contentLength(); - final long requestSize = UploadContext.class.isAssignableFrom(ctx.getClass()) - // Inline conditional is OK here CHECKSTYLE:OFF - ? ((UploadContext) ctx).contentLength() - : contentLengthInt; - // CHECKSTYLE:ON - - final InputStream input; // N.B. this is eventually closed in MultipartStream processing - if (sizeMax >= 0) { - if (requestSize != -1 && requestSize > sizeMax) { - throw new SizeLimitExceededException( - format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", - requestSize, sizeMax), - requestSize, sizeMax); - } - // N.B. this is eventually closed in MultipartStream processing - input = new LimitedInputStream(ctx.getInputStream(), sizeMax) { - @Override - protected void raiseError(final long pSizeMax, final long pCount) - throws IOException { - final FileUploadException ex = new SizeLimitExceededException( - format("the request was rejected because its size (%s) exceeds the configured maximum (%s)", - pCount, pSizeMax), - pCount, pSizeMax); - throw new FileUploadIOException(ex); - } - }; - } else { - input = ctx.getInputStream(); - } - - String charEncoding = fileUploadBase.getHeaderEncoding(); - if (charEncoding == null) { - charEncoding = ctx.getCharacterEncoding(); - } - - multiPartBoundary = fileUploadBase.getBoundary(contentType); - if (multiPartBoundary == null) { - IOUtils.closeQuietly(input); // avoid possible resource leak - throw new FileUploadException("the request was rejected because no multipart boundary was found"); - } - - progressNotifier = new MultipartStream.ProgressNotifier(fileUploadBase.getProgressListener(), requestSize); - try { - multiPartStream = new MultipartStream(input, multiPartBoundary, progressNotifier); - } catch (final IllegalArgumentException iae) { - IOUtils.closeQuietly(input); // avoid possible resource leak - throw new InvalidContentTypeException( - format("The boundary specified in the %s header is too long", FileUploadBase.CONTENT_TYPE), iae); - } - multiPartStream.setHeaderEncoding(charEncoding); - } - - public MultipartStream getMultiPartStream() throws FileUploadException, IOException { - if (multiPartStream == null) { - init(fileUploadBase, ctx); - } - return multiPartStream; - } - - /** - * Called for finding the next item, if any. - * - * @return True, if an next item was found, otherwise false. - * @throws IOException An I/O error occurred. - */ - private boolean findNextItem() throws FileUploadException, IOException { - if (eof) { - return false; - } - if (currentItem != null) { - currentItem.close(); - currentItem = null; - } - final MultipartStream multi = getMultiPartStream(); - for (; ; ) { - final boolean nextPart; - if (skipPreamble) { - nextPart = multi.skipPreamble(); - } else { - nextPart = multi.readBoundary(); - } - if (!nextPart) { - if (currentFieldName == null) { - // Outer multipart terminated -> No more data - eof = true; - return false; - } - // Inner multipart terminated -> Return to parsing the outer - multi.setBoundary(multiPartBoundary); - currentFieldName = null; - continue; - } - final FileItemHeaders headers = fileUploadBase.getParsedHeaders(multi.readHeaders()); - if (currentFieldName == null) { - // We're parsing the outer multipart - final String fieldName = fileUploadBase.getFieldName(headers); - if (fieldName != null) { - final String subContentType = headers.getHeader(FileUploadBase.CONTENT_TYPE); - if (subContentType != null - && subContentType.toLowerCase(Locale.ENGLISH) - .startsWith(FileUploadBase.MULTIPART_MIXED)) { - currentFieldName = fieldName; - // Multiple files associated with this field name - final byte[] subBoundary = fileUploadBase.getBoundary(subContentType); - multi.setBoundary(subBoundary); - skipPreamble = true; - continue; - } - final String fileName = fileUploadBase.getFileName(headers); - currentItem = new FileItemStreamImpl(this, fileName, - fieldName, headers.getHeader(FileUploadBase.CONTENT_TYPE), - fileName == null, getContentLength(headers)); - currentItem.setHeaders(headers); - progressNotifier.noteItem(); - itemValid = true; - return true; - } - } else { - final String fileName = fileUploadBase.getFileName(headers); - if (fileName != null) { - currentItem = new FileItemStreamImpl(this, fileName, - currentFieldName, - headers.getHeader(FileUploadBase.CONTENT_TYPE), - false, getContentLength(headers)); - currentItem.setHeaders(headers); - progressNotifier.noteItem(); - itemValid = true; - return true; - } - } - multi.discardBodyData(); - } - } - - private long getContentLength(final FileItemHeaders pHeaders) { - try { - return Long.parseLong(pHeaders.getHeader(FileUploadBase.CONTENT_LENGTH)); - } catch (final Exception e) { - return -1; - } - } - - /** - * Returns, whether another instance of {@link FileItemStream} - * is available. - * - * @return True, if one or more additional file items - * are available, otherwise false. - * @throws FileUploadException Parsing or processing the - * file item failed. - * @throws IOException Reading the file item failed. - */ - @Override - public boolean hasNext() throws FileUploadException, IOException { - if (eof) { - return false; - } - if (itemValid) { - return true; - } - try { - return findNextItem(); - } catch (final FileUploadIOException e) { - // unwrap encapsulated SizeException - throw (FileUploadException) e.getCause(); - } - } - - /** - * Returns the next available {@link FileItemStream}. - * - * @return FileItemStream instance, which provides - * access to the next file item. - * @throws NoSuchElementException No more items are - * available. Use {@link #hasNext()} to prevent this exception. - * @throws FileUploadException Parsing or processing the - * file item failed. - * @throws IOException Reading the file item failed. - */ - @Override - public FileItemStream next() throws FileUploadException, IOException { - if (eof || (!itemValid && !hasNext())) { - throw new NoSuchElementException(); - } - itemValid = false; - return currentItem; - } - - @Override - public List getFileItems() throws FileUploadException, IOException { - final List items = new ArrayList<>(); - while (hasNext()) { - final FileItemStream fis = next(); - final FileItem fi = fileUploadBase.getFileItemFactory().createItem(fis.getFieldName(), - fis.getContentType(), fis.isFormField(), fis.getName()); - items.add(fi); - } - return items; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java b/client/src/test/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java deleted file mode 100644 index 4884b18f63..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/impl/FileItemStreamImpl.java +++ /dev/null @@ -1,222 +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.commons.fileupload2.impl; - -import org.apache.commons.fileupload2.FileItemHeaders; -import org.apache.commons.fileupload2.FileItemStream; -import org.apache.commons.fileupload2.FileUploadException; -import org.apache.commons.fileupload2.InvalidFileNameException; -import org.apache.commons.fileupload2.MultipartStream.ItemInputStream; -import org.apache.commons.fileupload2.pub.FileSizeLimitExceededException; -import org.apache.commons.fileupload2.pub.FileUploadIOException; -import org.apache.commons.fileupload2.util.Closeable; -import org.apache.commons.fileupload2.util.LimitedInputStream; -import org.apache.commons.fileupload2.util.Streams; - -import java.io.IOException; -import java.io.InputStream; - -import static java.lang.String.format; - - -/** - * Default implementation of {@link FileItemStream}. - */ -public class FileItemStreamImpl implements FileItemStream { - /** - * The File Item iterator implementation. - * - * @see FileItemIteratorImpl - */ - private final FileItemIteratorImpl fileItemIteratorImpl; - - /** - * The file items content type. - */ - private final String contentType; - - /** - * The file items field name. - */ - private final String fieldName; - - /** - * The file items file name. - */ - private final String name; - - /** - * Whether the file item is a form field. - */ - private final boolean formField; - - /** - * The file items input stream. - */ - private final InputStream stream; - - /** - * The headers, if any. - */ - private FileItemHeaders headers; - - /** - * Creates a new instance. - * - * @param pFileItemIterator The {@link FileItemIteratorImpl iterator}, which returned this file - * item. - * @param pName The items file name, or null. - * @param pFieldName The items field name. - * @param pContentType The items content type, or null. - * @param pFormField Whether the item is a form field. - * @param pContentLength The items content length, if known, or -1 - * @throws IOException Creating the file item failed. - * @throws FileUploadException Parsing the incoming data stream failed. - */ - public FileItemStreamImpl(final FileItemIteratorImpl pFileItemIterator, final String pName, final String pFieldName, - final String pContentType, final boolean pFormField, - final long pContentLength) throws FileUploadException, IOException { - fileItemIteratorImpl = pFileItemIterator; - name = pName; - fieldName = pFieldName; - contentType = pContentType; - formField = pFormField; - final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax(); - if (fileSizeMax != -1 && pContentLength != -1 - && pContentLength > fileSizeMax) { - final FileSizeLimitExceededException e = - new FileSizeLimitExceededException( - format("The field %s exceeds its maximum permitted size of %s bytes.", - fieldName, fileSizeMax), - pContentLength, fileSizeMax); - e.setFileName(pName); - e.setFieldName(pFieldName); - throw new FileUploadIOException(e); - } - // OK to construct stream now - final ItemInputStream itemStream = fileItemIteratorImpl.getMultiPartStream().newInputStream(); - InputStream istream = itemStream; - if (fileSizeMax != -1) { - istream = new LimitedInputStream(istream, fileSizeMax) { - @Override - protected void raiseError(final long pSizeMax, final long pCount) - throws IOException { - itemStream.close(true); - final FileSizeLimitExceededException e = - new FileSizeLimitExceededException( - format("The field %s exceeds its maximum permitted size of %s bytes.", - fieldName, pSizeMax), - pCount, pSizeMax); - e.setFieldName(fieldName); - e.setFileName(name); - throw new FileUploadIOException(e); - } - }; - } - stream = istream; - } - - /** - * Returns the items content type, or null. - * - * @return Content type, if known, or null. - */ - @Override - public String getContentType() { - return contentType; - } - - /** - * Returns the items field name. - * - * @return Field name. - */ - @Override - public String getFieldName() { - return fieldName; - } - - /** - * Returns the items file name. - * - * @return File name, if known, or null. - * @throws InvalidFileNameException The file name contains a NUL character, - * which might be an indicator of a security attack. If you intend to - * use the file name anyways, catch the exception and use - * InvalidFileNameException#getName(). - */ - @Override - public String getName() { - return Streams.checkFileName(name); - } - - /** - * Returns, whether this is a form field. - * - * @return True, if the item is a form field, - * otherwise false. - */ - @Override - public boolean isFormField() { - return formField; - } - - /** - * Returns an input stream, which may be used to - * read the items contents. - * - * @return Opened input stream. - * @throws IOException An I/O error occurred. - */ - @Override - public InputStream openStream() throws IOException { - if (((Closeable) stream).isClosed()) { - throw new ItemSkippedException(); - } - return stream; - } - - /** - * Closes the file item. - * - * @throws IOException An I/O error occurred. - */ - public void close() throws IOException { - stream.close(); - } - - /** - * Returns the file item headers. - * - * @return The items header object - */ - @Override - public FileItemHeaders getHeaders() { - return headers; - } - - /** - * Sets the file item headers. - * - * @param pHeaders The items header object - */ - @Override - public void setHeaders(final FileItemHeaders pHeaders) { - headers = pHeaders; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/impl/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/impl/package-info.java deleted file mode 100644 index 93c87acb02..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/impl/package-info.java +++ /dev/null @@ -1,21 +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. - */ - -/** - * Implementations and exceptions utils. - */ -package org.apache.commons.fileupload2.impl; diff --git a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java b/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java deleted file mode 100644 index bc23460c5a..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileCleaner.java +++ /dev/null @@ -1,88 +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.commons.fileupload2.jaksrvlt; - - -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletContextEvent; -import jakarta.servlet.ServletContextListener; -import org.apache.commons.io.FileCleaningTracker; - -/** - * A servlet context listener, which ensures that the - * {@link FileCleaningTracker}'s reaper thread is terminated, - * when the web application is destroyed. - */ -public class JakSrvltFileCleaner implements ServletContextListener { - - /** - * Attribute name, which is used for storing an instance of - * {@link FileCleaningTracker} in the web application. - */ - public static final String FILE_CLEANING_TRACKER_ATTRIBUTE - = JakSrvltFileCleaner.class.getName() + ".FileCleaningTracker"; - - /** - * Returns the instance of {@link FileCleaningTracker}, which is - * associated with the given {@link ServletContext}. - * - * @param pServletContext The servlet context to query - * @return The contexts tracker - */ - public static FileCleaningTracker - getFileCleaningTracker(final ServletContext pServletContext) { - return (FileCleaningTracker) - pServletContext.getAttribute(FILE_CLEANING_TRACKER_ATTRIBUTE); - } - - /** - * Sets the instance of {@link FileCleaningTracker}, which is - * associated with the given {@link ServletContext}. - * - * @param pServletContext The servlet context to modify - * @param pTracker The tracker to set - */ - public static void setFileCleaningTracker(final ServletContext pServletContext, - final FileCleaningTracker pTracker) { - pServletContext.setAttribute(FILE_CLEANING_TRACKER_ATTRIBUTE, pTracker); - } - - /** - * Called when the web application is initialized. Does - * nothing. - * - * @param sce The servlet context, used for calling - * {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}. - */ - @Override - public void contextInitialized(final ServletContextEvent sce) { - setFileCleaningTracker(sce.getServletContext(), - new FileCleaningTracker()); - } - - /** - * Called when the web application is being destroyed. - * Calls {@link FileCleaningTracker#exitWhenFinished()}. - * - * @param sce The servlet context, used for calling - * {@link #getFileCleaningTracker(ServletContext)}. - */ - @Override - public void contextDestroyed(final ServletContextEvent sce) { - getFileCleaningTracker(sce.getServletContext()).exitWhenFinished(); - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java b/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java deleted file mode 100644 index dba4d8225c..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltFileUpload.java +++ /dev/null @@ -1,143 +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.commons.fileupload2.jaksrvlt; - -import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.fileupload2.FileItem; -import org.apache.commons.fileupload2.FileItemFactory; -import org.apache.commons.fileupload2.FileItemIterator; -import org.apache.commons.fileupload2.FileUpload; -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.FileUploadException; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - *

High level API for processing file uploads.

- * - *

This class handles multiple files per single HTML widget, sent using - * {@code multipart/mixed} encoding type, as specified by - * RFC 1867. Use {@link - * #parseRequest(HttpServletRequest)} to acquire a list of {@link - * 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.

- */ -public class JakSrvltFileUpload extends FileUpload { - - /** - * Constant for HTTP POST method. - */ - private static final String POST_METHOD = "POST"; - - // ---------------------------------------------------------- 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 {@code true} if the request is multipart; - * {@code false} otherwise. - */ - public static final boolean isMultipartContent( - final HttpServletRequest request) { - if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) { - return false; - } - return FileUploadBase.isMultipartContent(new JakSrvltRequestContext(request)); - } - - // ----------------------------------------------------------- Constructors - - /** - * Constructs an uninitialized instance of this class. A factory must be - * configured, using {@code setFileItemFactory()}, before attempting - * to parse requests. - * - * @see FileUpload#FileUpload(FileItemFactory) - */ - public JakSrvltFileUpload() { - } - - /** - * Constructs an instance of this class which uses the supplied factory to - * create {@code FileItem} instances. - * - * @param fileItemFactory The factory to use for creating file items. - * @see FileUpload#FileUpload() - */ - public JakSrvltFileUpload(final FileItemFactory fileItemFactory) { - super(fileItemFactory); - } - - // --------------------------------------------------------- Public methods - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The servlet request to be parsed. - * @return A list of {@code 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(final HttpServletRequest request) throws FileUploadException { - return parseRequest(new JakSrvltRequestContext(request)); - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The servlet request to be parsed. - * @return A map of {@code FileItem} instances parsed from the request. - * @throws FileUploadException if there are problems reading/parsing - * the request or storing files. - * @since 1.3 - */ - public Map> parseParameterMap(final HttpServletRequest request) - throws FileUploadException { - return parseParameterMap(new JakSrvltRequestContext(request)); - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The servlet request to be parsed. - * @return An iterator to instances of {@code 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(final HttpServletRequest request) - throws FileUploadException, IOException { - return super.getItemIterator(new JakSrvltRequestContext(request)); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java b/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java deleted file mode 100644 index 8bbc50e958..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/JakSrvltRequestContext.java +++ /dev/null @@ -1,128 +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.commons.fileupload2.jaksrvlt; - -import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.UploadContext; - -import java.io.IOException; -import java.io.InputStream; - -import static java.lang.String.format; - -/** - *

Provides access to the request information needed for a request made to - * an HTTP servlet.

- * - * @since 1.1 - */ -public class JakSrvltRequestContext implements UploadContext { - - // ----------------------------------------------------- Instance Variables - - /** - * The request for which the context is being provided. - */ - private final HttpServletRequest request; - - // ----------------------------------------------------------- Constructors - - /** - * Construct a context for this request. - * - * @param request The request to which this context applies. - */ - public JakSrvltRequestContext(final HttpServletRequest request) { - this.request = request; - } - - // --------------------------------------------------------- Public Methods - - /** - * Retrieve the character encoding for the request. - * - * @return The character encoding for the request. - */ - @Override - public String getCharacterEncoding() { - return request.getCharacterEncoding(); - } - - /** - * Retrieve the content type of the request. - * - * @return The content type of the request. - */ - @Override - public String getContentType() { - return request.getContentType(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @deprecated 1.3 Use {@link #contentLength()} instead - */ - @Override - @Deprecated - public int getContentLength() { - return request.getContentLength(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @since 1.3 - */ - @Override - public long contentLength() { - long size; - try { - size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH)); - } catch (final NumberFormatException e) { - size = request.getContentLength(); - } - return size; - } - - /** - * Retrieve the input stream for the request. - * - * @return The input stream for the request. - * @throws IOException if a problem occurs. - */ - @Override - 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 format("ContentLength=%s, ContentType=%s", - this.contentLength(), - this.getContentType()); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/package-info.java deleted file mode 100644 index 796830f623..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/jaksrvlt/package-info.java +++ /dev/null @@ -1,41 +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. - */ - -/** - *

- * An implementation of - * {@link org.apache.commons.fileupload2.FileUpload FileUpload} - * for use in servlets conforming to the namespace {@code jakarta.servlet}. - * - *

- *

- * The following code fragment demonstrates typical usage. - *

- *
- *        DiskFileItemFactory factory = new DiskFileItemFactory();
- *        // Configure the factory here, if desired.
- *        JakSrvltFileUpload upload = new JakSrvltFileUpload(factory);
- *        // Configure the uploader here, if desired.
- *        List fileItems = upload.parseRequest(request);
- * 
- *

- * Please see the FileUpload - * User Guide - * for further details and examples of how to use this package. - *

- */ -package org.apache.commons.fileupload2.jaksrvlt; diff --git a/client/src/test/java/org/apache/commons/fileupload2/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/package-info.java deleted file mode 100644 index e91d991abf..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/package-info.java +++ /dev/null @@ -1,85 +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. - */ - -/** - *

- * A component for handling HTML file uploads as specified by - * RFC 1867. - * This component provides support for uploads within both servlets (JSR 53) - * and portlets (JSR 168). - *

- *

- * While this package provides the generic functionality for file uploads, - * these classes are not typically used directly. Instead, normal usage - * involves one of the provided extensions of - * {@link org.apache.commons.fileupload2.FileUpload FileUpload} such as - * {@link org.apache.commons.fileupload2.servlet.ServletFileUpload ServletFileUpload} - * or - * {@link org.apache.commons.fileupload2.portlet.PortletFileUpload PortletFileUpload}, - * together with a factory for - * {@link org.apache.commons.fileupload2.FileItem FileItem} instances, - * such as - * {@link org.apache.commons.fileupload2.disk.DiskFileItemFactory DiskFileItemFactory}. - *

- *

- * The following is a brief example of typical usage in a servlet, storing - * the uploaded files on disk. - *

- *
public void doPost(HttpServletRequest req, HttpServletResponse res) {
- *   DiskFileItemFactory factory = new DiskFileItemFactory();
- *   // maximum size that will be stored in memory
- *   factory.setSizeThreshold(4096);
- *   // the location for saving data that is larger than getSizeThreshold()
- *   factory.setRepository(new File("/tmp"));
- *
- *   ServletFileUpload upload = new ServletFileUpload(factory);
- *   // maximum size before a FileUploadException will be thrown
- *   upload.setSizeMax(1000000);
- *
- *   List fileItems = upload.parseRequest(req);
- *   // assume we know there are two files. The first file is a small
- *   // text file, the second is unknown and is written to a file on
- *   // the server
- *   Iterator i = fileItems.iterator();
- *   String comment = ((FileItem)i.next()).getString();
- *   FileItem fi = (FileItem)i.next();
- *   // file name on the client
- *   String fileName = fi.getName();
- *   // save comment and file name to database
- *   ...
- *   // write the file
- *   fi.write(new File("/www/uploads/", fileName));
- * }
- * 
- *

- * In the example above, the first file is loaded into memory as a - * {@code String}. Before calling the {@code getString} method, - * the data may have been in memory or on disk depending on its size. The - * second file we assume it will be large and therefore never explicitly - * load it into memory, though if it is less than 4096 bytes it will be - * in memory before it is written to its final location. When writing to - * the final location, if the data is larger than the threshold, an attempt - * is made to rename the temporary file to the given location. If it cannot - * be renamed, it is streamed to the new location. - *

- *

- * Please see the FileUpload - * User Guide - * for further details and examples of how to use this package. - *

- */ -package org.apache.commons.fileupload2; diff --git a/client/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java b/client/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java deleted file mode 100644 index cc59fe92ef..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/portlet/PortletFileUpload.java +++ /dev/null @@ -1,134 +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.commons.fileupload2.portlet; - -import org.apache.commons.fileupload2.FileItem; -import org.apache.commons.fileupload2.FileItemFactory; -import org.apache.commons.fileupload2.FileItemIterator; -import org.apache.commons.fileupload2.FileUpload; -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.FileUploadException; - -import javax.portlet.ActionRequest; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - *

High level API for processing file uploads.

- * - *

This class handles multiple files per single HTML widget, sent using - * {@code multipart/mixed} encoding type, as specified by - * RFC 1867. Use - * {@link org.apache.commons.fileupload2.servlet.ServletFileUpload - * #parseRequest(javax.servlet.http.HttpServletRequest)} to acquire a list - * of {@link FileItem FileItems} 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.

- * - * @since 1.1 - */ -public class PortletFileUpload extends FileUpload { - - // ---------------------------------------------------------- Class methods - - /** - * Utility method that determines whether the request contains multipart - * content. - * - * @param request The portlet request to be evaluated. Must be non-null. - * @return {@code true} if the request is multipart; - * {@code false} otherwise. - */ - public static final boolean isMultipartContent(final ActionRequest request) { - return FileUploadBase.isMultipartContent(new PortletRequestContext(request)); - } - - // ----------------------------------------------------------- Constructors - - /** - * Constructs an uninitialized instance of this class. A factory must be - * configured, using {@code setFileItemFactory()}, before attempting - * to parse requests. - * - * @see FileUpload#FileUpload(FileItemFactory) - */ - public PortletFileUpload() { - } - - /** - * Constructs an instance of this class which uses the supplied factory to - * create {@code FileItem} instances. - * - * @param fileItemFactory The factory to use for creating file items. - * @see FileUpload#FileUpload() - */ - public PortletFileUpload(final FileItemFactory fileItemFactory) { - super(fileItemFactory); - } - - // --------------------------------------------------------- Public methods - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The portlet request to be parsed. - * @return A list of {@code 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(final ActionRequest request) throws FileUploadException { - return parseRequest(new PortletRequestContext(request)); - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The portlet request to be parsed. - * @return A map of {@code FileItem} instances parsed from the request. - * @throws FileUploadException if there are problems reading/parsing - * the request or storing files. - * @since 1.3 - */ - public Map> parseParameterMap(final ActionRequest request) throws FileUploadException { - return parseParameterMap(new PortletRequestContext(request)); - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The portlet request to be parsed. - * @return An iterator to instances of {@code 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(final ActionRequest request) throws FileUploadException, IOException { - return super.getItemIterator(new PortletRequestContext(request)); - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java b/client/src/test/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java deleted file mode 100644 index 2beba44b0e..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/portlet/PortletRequestContext.java +++ /dev/null @@ -1,130 +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.commons.fileupload2.portlet; - -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.UploadContext; - -import javax.portlet.ActionRequest; -import java.io.IOException; -import java.io.InputStream; - -import static java.lang.String.format; - -/** - *

Provides access to the request information needed for a request made to - * a portlet.

- * - * @since 1.1 - */ -public class PortletRequestContext implements UploadContext { - - // ----------------------------------------------------- Instance Variables - - /** - * The request for which the context is being provided. - */ - private final ActionRequest request; - - - // ----------------------------------------------------------- Constructors - - /** - * Construct a context for this request. - * - * @param request The request to which this context applies. - */ - public PortletRequestContext(final ActionRequest request) { - this.request = request; - } - - - // --------------------------------------------------------- Public Methods - - /** - * Retrieve the character encoding for the request. - * - * @return The character encoding for the request. - */ - @Override - public String getCharacterEncoding() { - return request.getCharacterEncoding(); - } - - /** - * Retrieve the content type of the request. - * - * @return The content type of the request. - */ - @Override - public String getContentType() { - return request.getContentType(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @deprecated 1.3 Use {@link #contentLength()} instead - */ - @Override - @Deprecated - public int getContentLength() { - return request.getContentLength(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @since 1.3 - */ - @Override - public long contentLength() { - long size; - try { - size = Long.parseLong(request.getProperty(FileUploadBase.CONTENT_LENGTH)); - } catch (final NumberFormatException e) { - size = request.getContentLength(); - } - return size; - } - - /** - * Retrieve the input stream for the request. - * - * @return The input stream for the request. - * @throws IOException if a problem occurs. - */ - @Override - public InputStream getInputStream() throws IOException { - return request.getPortletInputStream(); - } - - /** - * Returns a string representation of this object. - * - * @return a string representation of this object. - */ - @Override - public String toString() { - return format("ContentLength=%s, ContentType=%s", - this.contentLength(), - this.getContentType()); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/portlet/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/portlet/package-info.java deleted file mode 100644 index d5c2c3bfea..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/portlet/package-info.java +++ /dev/null @@ -1,45 +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. - */ - -/** - *

- * An implementation of - * {@link org.apache.commons.fileupload2.FileUpload FileUpload} - * for use in portlets conforming to JSR 168. This implementation requires - * only access to the portlet's current {@code ActionRequest} instance, - * and a suitable - * {@link org.apache.commons.fileupload2.FileItemFactory FileItemFactory} - * implementation, such as - * {@link org.apache.commons.fileupload2.disk.DiskFileItemFactory DiskFileItemFactory}. - *

- *

- * The following code fragment demonstrates typical usage. - *

- *
- *        DiskFileItemFactory factory = new DiskFileItemFactory();
- *        // Configure the factory here, if desired.
- *        PortletFileUpload upload = new PortletFileUpload(factory);
- *        // Configure the uploader here, if desired.
- *        List fileItems = upload.parseRequest(request);
- * 
- *

- * Please see the FileUpload - * User Guide - * for further details and examples of how to use this package. - *

- */ -package org.apache.commons.fileupload2.portlet; diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java b/client/src/test/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java deleted file mode 100644 index b87b8dc5e7..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/FileSizeLimitExceededException.java +++ /dev/null @@ -1,94 +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.commons.fileupload2.pub; - -/** - * Thrown to indicate that A files size exceeds the configured maximum. - */ -public class FileSizeLimitExceededException - extends SizeException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = 8150776562029630058L; - - /** - * File name of the item, which caused the exception. - */ - private String fileName; - - /** - * Field name of the item, which caused the exception. - */ - private String fieldName; - - /** - * Constructs a {@code SizeExceededException} with - * the specified detail message, and actual and permitted sizes. - * - * @param message The detail message. - * @param actual The actual request size. - * @param permitted The maximum permitted request size. - */ - public FileSizeLimitExceededException(final String message, final long actual, - final long permitted) { - super(message, actual, permitted); - } - - /** - * Returns the file name of the item, which caused the - * exception. - * - * @return File name, if known, or null. - */ - public String getFileName() { - return fileName; - } - - /** - * Sets the file name of the item, which caused the - * exception. - * - * @param pFileName the file name of the item, which caused the exception. - */ - public void setFileName(final String pFileName) { - fileName = pFileName; - } - - /** - * Returns the field name of the item, which caused the - * exception. - * - * @return Field name, if known, or null. - */ - public String getFieldName() { - return fieldName; - } - - /** - * Sets the field name of the item, which caused the - * exception. - * - * @param pFieldName the field name of the item, - * which caused the exception. - */ - public void setFieldName(final String pFieldName) { - fieldName = pFieldName; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java b/client/src/test/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java deleted file mode 100644 index e8245e4e50..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/FileUploadIOException.java +++ /dev/null @@ -1,62 +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.commons.fileupload2.pub; - -import org.apache.commons.fileupload2.FileUploadException; - -import java.io.IOException; - -/** - * This exception is thrown for hiding an inner - * {@link FileUploadException} in an {@link IOException}. - */ -public class FileUploadIOException extends IOException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = -7047616958165584154L; - - /** - * The exceptions cause; we overwrite the parent - * classes field, which is available since Java - * 1.4 only. - */ - private final FileUploadException cause; - - /** - * Creates a {@code FileUploadIOException} with the - * given cause. - * - * @param pCause The exceptions cause, if any, or null. - */ - public FileUploadIOException(final FileUploadException pCause) { - // We're not doing super(pCause) cause of 1.3 compatibility. - cause = pCause; - } - - /** - * Returns the exceptions cause. - * - * @return The exceptions cause, if any, or null. - */ - @Override - public Throwable getCause() { - return cause; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java b/client/src/test/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java deleted file mode 100644 index a35d4d54a7..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/IOFileUploadException.java +++ /dev/null @@ -1,61 +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.commons.fileupload2.pub; - -import org.apache.commons.fileupload2.FileUploadException; - -import java.io.IOException; - -/** - * Thrown to indicate an IOException. - */ -public class IOFileUploadException extends FileUploadException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = 1749796615868477269L; - - /** - * The exceptions cause; we overwrite the parent - * classes field, which is available since Java - * 1.4 only. - */ - private final IOException cause; - - /** - * Creates a new instance with the given cause. - * - * @param pMsg The detail message. - * @param pException The exceptions cause. - */ - public IOFileUploadException(final String pMsg, final IOException pException) { - super(pMsg); - cause = pException; - } - - /** - * Returns the exceptions cause. - * - * @return The exceptions cause, if any, or null. - */ - @Override - public Throwable getCause() { - return cause; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/InvalidContentTypeException.java b/client/src/test/java/org/apache/commons/fileupload2/pub/InvalidContentTypeException.java deleted file mode 100644 index 4df548a4b8..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/InvalidContentTypeException.java +++ /dev/null @@ -1,60 +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.commons.fileupload2.pub; - -import org.apache.commons.fileupload2.FileUploadException; - -/** - * Thrown to indicate that the request is not a multipart request. - */ -public class InvalidContentTypeException - extends FileUploadException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = -9073026332015646668L; - - /** - * Constructs a {@code InvalidContentTypeException} with no - * detail message. - */ - public InvalidContentTypeException() { - } - - /** - * Constructs an {@code InvalidContentTypeException} with - * the specified detail message. - * - * @param message The detail message. - */ - public InvalidContentTypeException(final String message) { - super(message); - } - - /** - * Constructs an {@code InvalidContentTypeException} with - * the specified detail message and cause. - * - * @param msg The detail message. - * @param cause the original cause - * @since 1.3.1 - */ - public InvalidContentTypeException(final String msg, final Throwable cause) { - super(msg, cause); - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/SizeException.java b/client/src/test/java/org/apache/commons/fileupload2/pub/SizeException.java deleted file mode 100644 index f075b5e336..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/SizeException.java +++ /dev/null @@ -1,75 +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.commons.fileupload2.pub; - -import org.apache.commons.fileupload2.FileUploadException; - -/** - * This exception is thrown, if a requests permitted size - * is exceeded. - */ -abstract class SizeException extends FileUploadException { - - /** - * Serial version UID, being used, if serialized. - */ - private static final long serialVersionUID = -8776225574705254126L; - - /** - * The actual size of the request. - */ - private final long actual; - - /** - * The maximum permitted size of the request. - */ - private final long permitted; - - /** - * Creates a new instance. - * - * @param message The detail message. - * @param actual The actual number of bytes in the request. - * @param permitted The requests size limit, in bytes. - */ - protected SizeException(final String message, final long actual, final long permitted) { - super(message); - this.actual = actual; - this.permitted = permitted; - } - - /** - * Retrieves the actual size of the request. - * - * @return The actual size of the request. - * @since 1.3 - */ - public long getActualSize() { - return actual; - } - - /** - * Retrieves the permitted size of the request. - * - * @return The permitted size of the request. - * @since 1.3 - */ - public long getPermittedSize() { - return permitted; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java b/client/src/test/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java deleted file mode 100644 index 2e4056250a..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/SizeLimitExceededException.java +++ /dev/null @@ -1,43 +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.commons.fileupload2.pub; - -/** - * Thrown to indicate that the request size exceeds the configured maximum. - */ -public class SizeLimitExceededException - extends SizeException { - - /** - * The exceptions UID, for serializing an instance. - */ - private static final long serialVersionUID = -2474893167098052828L; - - /** - * Constructs a {@code SizeExceededException} with - * the specified detail message, and actual and permitted sizes. - * - * @param message The detail message. - * @param actual The actual request size. - * @param permitted The maximum permitted request size. - */ - public SizeLimitExceededException(final String message, final long actual, - final long permitted) { - super(message, actual, permitted); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/pub/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/pub/package-info.java deleted file mode 100644 index 1b8698b53d..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/pub/package-info.java +++ /dev/null @@ -1,22 +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. - */ - -/** - * Exceptions, and other classes, that are known to be used outside - * of FileUpload. - */ -package org.apache.commons.fileupload2.pub; diff --git a/client/src/test/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java b/client/src/test/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java deleted file mode 100644 index 9a096ce0e0..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/servlet/FileCleanerCleanup.java +++ /dev/null @@ -1,88 +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.commons.fileupload2.servlet; - -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletContextEvent; -import jakarta.servlet.ServletContextListener; -import org.apache.commons.io.FileCleaningTracker; - -/** - * A servlet context listener, which ensures that the - * {@link FileCleaningTracker}'s reaper thread is terminated, - * when the web application is destroyed. - */ -public class FileCleanerCleanup implements ServletContextListener { - - /** - * Attribute name, which is used for storing an instance of - * {@link FileCleaningTracker} in the web application. - */ - public static final String FILE_CLEANING_TRACKER_ATTRIBUTE - = FileCleanerCleanup.class.getName() + ".FileCleaningTracker"; - - /** - * Returns the instance of {@link FileCleaningTracker}, which is - * associated with the given {@link ServletContext}. - * - * @param pServletContext The servlet context to query - * @return The contexts tracker - */ - public static FileCleaningTracker - getFileCleaningTracker(final ServletContext pServletContext) { - return (FileCleaningTracker) - pServletContext.getAttribute(FILE_CLEANING_TRACKER_ATTRIBUTE); - } - - /** - * Sets the instance of {@link FileCleaningTracker}, which is - * associated with the given {@link ServletContext}. - * - * @param pServletContext The servlet context to modify - * @param pTracker The tracker to set - */ - public static void setFileCleaningTracker(final ServletContext pServletContext, - final FileCleaningTracker pTracker) { - pServletContext.setAttribute(FILE_CLEANING_TRACKER_ATTRIBUTE, pTracker); - } - - /** - * Called when the web application is initialized. Does - * nothing. - * - * @param sce The servlet context, used for calling - * {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}. - */ - @Override - public void contextInitialized(final ServletContextEvent sce) { - setFileCleaningTracker(sce.getServletContext(), - new FileCleaningTracker()); - } - - /** - * Called when the web application is being destroyed. - * Calls {@link FileCleaningTracker#exitWhenFinished()}. - * - * @param sce The servlet context, used for calling - * {@link #getFileCleaningTracker(ServletContext)}. - */ - @Override - public void contextDestroyed(final ServletContextEvent sce) { - getFileCleaningTracker(sce.getServletContext()).exitWhenFinished(); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java b/client/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java deleted file mode 100644 index 8b00f2c50a..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/servlet/ServletFileUpload.java +++ /dev/null @@ -1,143 +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.commons.fileupload2.servlet; - -import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.fileupload2.FileItem; -import org.apache.commons.fileupload2.FileItemFactory; -import org.apache.commons.fileupload2.FileItemIterator; -import org.apache.commons.fileupload2.FileUpload; -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.FileUploadException; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - *

High level API for processing file uploads.

- * - *

This class handles multiple files per single HTML widget, sent using - * {@code multipart/mixed} encoding type, as specified by - * RFC 1867. Use {@link - * #parseRequest(HttpServletRequest)} to acquire a list of {@link - * 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.

- */ -public class ServletFileUpload extends FileUpload { - - /** - * Constant for HTTP POST method. - */ - private static final String POST_METHOD = "POST"; - - // ---------------------------------------------------------- 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 {@code true} if the request is multipart; - * {@code false} otherwise. - */ - public static final boolean isMultipartContent( - final HttpServletRequest request) { - if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) { - return false; - } - return FileUploadBase.isMultipartContent(new ServletRequestContext(request)); - } - - // ----------------------------------------------------------- Constructors - - /** - * Constructs an uninitialized instance of this class. A factory must be - * configured, using {@code setFileItemFactory()}, before attempting - * to parse requests. - * - * @see FileUpload#FileUpload(FileItemFactory) - */ - public ServletFileUpload() { - } - - /** - * Constructs an instance of this class which uses the supplied factory to - * create {@code FileItem} instances. - * - * @param fileItemFactory The factory to use for creating file items. - * @see FileUpload#FileUpload() - */ - public ServletFileUpload(final FileItemFactory fileItemFactory) { - super(fileItemFactory); - } - - // --------------------------------------------------------- Public methods - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The servlet request to be parsed. - * @return A list of {@code 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(final HttpServletRequest request) - throws FileUploadException { - return parseRequest(new ServletRequestContext(request)); - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The servlet request to be parsed. - * @return A map of {@code FileItem} instances parsed from the request. - * @throws FileUploadException if there are problems reading/parsing - * the request or storing files. - * @since 1.3 - */ - public Map> parseParameterMap(final HttpServletRequest request) - throws FileUploadException { - return parseParameterMap(new ServletRequestContext(request)); - } - - /** - * Processes an RFC 1867 - * compliant {@code multipart/form-data} stream. - * - * @param request The servlet request to be parsed. - * @return An iterator to instances of {@code 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(final HttpServletRequest request) - throws FileUploadException, IOException { - return getItemIterator(new ServletRequestContext(request)); - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java b/client/src/test/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java deleted file mode 100644 index 246f21f1ae..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/servlet/ServletRequestContext.java +++ /dev/null @@ -1,128 +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.commons.fileupload2.servlet; - -import jakarta.servlet.http.HttpServletRequest; -import org.apache.commons.fileupload2.FileUploadBase; -import org.apache.commons.fileupload2.UploadContext; - -import java.io.IOException; -import java.io.InputStream; - -import static java.lang.String.format; - -/** - *

Provides access to the request information needed for a request made to - * an HTTP servlet.

- * - * @since 1.1 - */ -public class ServletRequestContext implements UploadContext { - - // ----------------------------------------------------- Instance Variables - - /** - * The request for which the context is being provided. - */ - private final HttpServletRequest request; - - // ----------------------------------------------------------- Constructors - - /** - * Construct a context for this request. - * - * @param request The request to which this context applies. - */ - public ServletRequestContext(final HttpServletRequest request) { - this.request = request; - } - - // --------------------------------------------------------- Public Methods - - /** - * Retrieve the character encoding for the request. - * - * @return The character encoding for the request. - */ - @Override - public String getCharacterEncoding() { - return request.getCharacterEncoding(); - } - - /** - * Retrieve the content type of the request. - * - * @return The content type of the request. - */ - @Override - public String getContentType() { - return request.getContentType(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @deprecated 1.3 Use {@link #contentLength()} instead - */ - @Override - @Deprecated - public int getContentLength() { - return request.getContentLength(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - * @since 1.3 - */ - @Override - public long contentLength() { - long size; - try { - size = Long.parseLong(request.getHeader(FileUploadBase.CONTENT_LENGTH)); - } catch (final NumberFormatException e) { - size = request.getContentLength(); - } - return size; - } - - /** - * Retrieve the input stream for the request. - * - * @return The input stream for the request. - * @throws IOException if a problem occurs. - */ - @Override - 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 format("ContentLength=%s, ContentType=%s", - contentLength(), - getContentType()); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/servlet/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/servlet/package-info.java deleted file mode 100644 index 06b0cb8704..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/servlet/package-info.java +++ /dev/null @@ -1,45 +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. - */ - -/** - *

- * An implementation of - * {@link org.apache.commons.fileupload2.FileUpload FileUpload} - * for use in servlets conforming to JSR 53. This implementation requires - * only access to the servlet's current {@code HttpServletRequest} - * instance, and a suitable - * {@link org.apache.commons.fileupload2.FileItemFactory FileItemFactory} - * implementation, such as - * {@link org.apache.commons.fileupload2.disk.DiskFileItemFactory DiskFileItemFactory}. - *

- *

- * The following code fragment demonstrates typical usage. - *

- *
- *        DiskFileItemFactory factory = new DiskFileItemFactory();
- *        // Configure the factory here, if desired.
- *        ServletFileUpload upload = new ServletFileUpload(factory);
- *        // Configure the uploader here, if desired.
- *        List fileItems = upload.parseRequest(request);
- * 
- *

- * Please see the FileUpload - * User Guide - * for further details and examples of how to use this package. - *

- */ -package org.apache.commons.fileupload2.servlet; diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/Closeable.java b/client/src/test/java/org/apache/commons/fileupload2/util/Closeable.java deleted file mode 100644 index dce76f8b39..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/Closeable.java +++ /dev/null @@ -1,41 +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.commons.fileupload2.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/client/src/test/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java b/client/src/test/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java deleted file mode 100644 index d4413d174b..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/FileItemHeadersImpl.java +++ /dev/null @@ -1,95 +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.commons.fileupload2.util; - -import org.apache.commons.fileupload2.FileItemHeaders; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -/** - * Default implementation of the {@link FileItemHeaders} interface. - * - * @since 1.2.1 - */ -public class FileItemHeadersImpl implements FileItemHeaders, Serializable { - - /** - * Serial version UID, being used, if serialized. - */ - private static final long serialVersionUID = -4455695752627032559L; - - /** - * Map of {@code String} keys to a {@code List} of - * {@code String} instances. - */ - private final Map> headerNameToValueListMap = new LinkedHashMap<>(); - - /** - * {@inheritDoc} - */ - @Override - public String getHeader(final String name) { - final String nameLower = name.toLowerCase(Locale.ENGLISH); - final List headerValueList = headerNameToValueListMap.get(nameLower); - if (null == headerValueList) { - return null; - } - return headerValueList.get(0); - } - - /** - * {@inheritDoc} - */ - @Override - public Iterator getHeaderNames() { - return headerNameToValueListMap.keySet().iterator(); - } - - /** - * {@inheritDoc} - */ - @Override - public Iterator getHeaders(final String name) { - final String nameLower = name.toLowerCase(Locale.ENGLISH); - List headerValueList = headerNameToValueListMap.get(nameLower); - if (null == headerValueList) { - headerValueList = Collections.emptyList(); - } - 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(final String name, final String value) { - final String nameLower = name.toLowerCase(Locale.ENGLISH); - final List headerValueList = headerNameToValueListMap. - computeIfAbsent(nameLower, k -> new ArrayList<>()); - headerValueList.add(value); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/LimitedInputStream.java b/client/src/test/java/org/apache/commons/fileupload2/util/LimitedInputStream.java deleted file mode 100644 index ec8c4d8301..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/LimitedInputStream.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.commons.fileupload2.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 final long sizeMax; - - /** - * The current number of bytes. - */ - private long count; - - /** - * Whether this stream is already closed. - */ - private boolean closed; - - /** - * Creates a new instance. - * - * @param inputStream 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(final InputStream inputStream, final long pSizeMax) { - super(inputStream); - 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 {@code int} in the range - * {@code 0} to {@code 255}. If no byte is available - * because the end of the stream has been reached, the value - * {@code -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 {@code in.read()} and returns the result. - * - * @return the next byte of data, or {@code -1} if the end of the - * stream is reached. - * @throws IOException if an I/O error occurs. - * @see FilterInputStream#in - */ - @Override - public int read() throws IOException { - final int res = super.read(); - if (res != -1) { - count++; - checkLimit(); - } - return res; - } - - /** - * Reads up to {@code len} bytes of data from this input stream - * into an array of bytes. If {@code len} is not zero, the method - * blocks until some input is available; otherwise, no - * bytes are read and {@code 0} is returned. - *

- * This method simply performs {@code 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 - * {@code b}. - * @param len the maximum number of bytes read. - * @return the total number of bytes read into the buffer, or - * {@code -1} if there is no more data because the end of - * the stream has been reached. - * @throws NullPointerException If {@code b} is {@code null}. - * @throws IndexOutOfBoundsException If {@code off} is negative, - * {@code len} is negative, or {@code len} is greater than - * {@code b.length - off} - * @throws IOException if an I/O error occurs. - * @see FilterInputStream#in - */ - @Override - public int read(final byte[] b, final int off, final int len) throws IOException { - final 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. - */ - @Override - public boolean isClosed() throws IOException { - return closed; - } - - /** - * Closes this input stream and releases any system resources - * associated with the stream. - * This - * method simply performs {@code in.close()}. - * - * @throws IOException if an I/O error occurs. - * @see FilterInputStream#in - */ - @Override - public void close() throws IOException { - closed = true; - super.close(); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/Streams.java b/client/src/test/java/org/apache/commons/fileupload2/util/Streams.java deleted file mode 100644 index 07faf497cf..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/Streams.java +++ /dev/null @@ -1,186 +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.commons.fileupload2.util; - -import org.apache.commons.fileupload2.InvalidFileNameException; - -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)}. - */ - public 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 inputStream The input stream, which is being read. - * It is guaranteed, that {@link InputStream#close()} is called - * on the stream. - * @param outputStream The output stream, to which data should - * be written. May be null, in which case the input streams - * contents are simply discarded. - * @param closeOutputStream 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(final InputStream inputStream, final OutputStream outputStream, - final boolean closeOutputStream) - throws IOException { - return copy(inputStream, outputStream, closeOutputStream, new byte[DEFAULT_BUFFER_SIZE]); - } - - /** - * Copies the contents of the given {@link InputStream} - * to the given {@link OutputStream}. - * - * @param inputStream The input stream, which is being read. - * It is guaranteed, that {@link InputStream#close()} is called - * on the stream. - * @param outputStream The output stream, to which data should - * be written. May be null, in which case the input streams - * contents are simply discarded. - * @param closeOutputStream True guarantees, that {@link OutputStream#close()} - * is called on the stream. False indicates, that only - * {@link OutputStream#flush()} should be called finally. - * @param buffer 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(final InputStream inputStream, - final OutputStream outputStream, final boolean closeOutputStream, - final byte[] buffer) - throws IOException { - try (OutputStream out = outputStream; - InputStream in = inputStream) { - long total = 0; - for (; ; ) { - final int res = in.read(buffer); - if (res == -1) { - break; - } - if (res > 0) { - total += res; - if (out != null) { - out.write(buffer, 0, res); - } - } - } - if (out != null) { - if (closeOutputStream) { - out.close(); - } else { - out.flush(); - } - } - in.close(); - return total; - } - } - - /** - * This convenience method allows to read a - * {@link org.apache.commons.fileupload2.FileItemStream}'s - * content into a string. The platform's default character encoding - * is used for converting bytes into characters. - * - * @param inputStream The input stream to read. - * @return The streams contents, as a string. - * @throws IOException An I/O error occurred. - * @see #asString(InputStream, String) - */ - public static String asString(final InputStream inputStream) throws IOException { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - copy(inputStream, baos, true); - return baos.toString(); - } - - /** - * This convenience method allows to read a - * {@link org.apache.commons.fileupload2.FileItemStream}'s - * content into a string, using the given character encoding. - * - * @param inputStream The input stream to read. - * @param encoding The character encoding, typically "UTF-8". - * @return The streams contents, as a string. - * @throws IOException An I/O error occurred. - * @see #asString(InputStream) - */ - public static String asString(final InputStream inputStream, final String encoding) - throws IOException { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - copy(inputStream, baos, true); - return baos.toString(encoding); - } - - /** - * Checks, whether the given file name is valid in the sense, - * that it doesn't contain any NUL characters. If the file name - * is valid, it will be returned without any modifications. Otherwise, - * an {@link InvalidFileNameException} is raised. - * - * @param fileName The file name to check - * @return Unmodified file name, if valid. - * @throws InvalidFileNameException The file name was found to be invalid. - */ - public static String checkFileName(final String fileName) { - if (fileName != null && fileName.indexOf('\u0000') != -1) { - // pFileName.replace("\u0000", "\\0") - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < fileName.length(); i++) { - final char c = fileName.charAt(i); - switch (c) { - case 0: - sb.append("\\0"); - break; - default: - sb.append(c); - break; - } - } - throw new InvalidFileNameException(fileName, - "Invalid file name: " + sb); - } - return fileName; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java b/client/src/test/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java deleted file mode 100644 index b61c2b921f..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/mime/Base64Decoder.java +++ /dev/null @@ -1,150 +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.commons.fileupload2.util.mime; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; - -/** - * @since 1.3 - */ -final class Base64Decoder { - - /** - * Decoding table value for invalid bytes. - */ - private static final byte INVALID_BYTE = -1; // must be outside range 0-63 - - /** - * Decoding table value for padding bytes, so can detect PAD after conversion. - */ - private static final int PAD_BYTE = -2; // must be outside range 0-63 - - /** - * Mask to treat byte as unsigned integer. - */ - private static final int MASK_BYTE_UNSIGNED = 0xFF; - - /** - * Number of bytes per encoded chunk - 4 6bit bytes produce 3 8bit bytes on output. - */ - private static final int INPUT_BYTES_PER_CHUNK = 4; - - /** - * Set up the encoding table. - */ - private static final byte[] ENCODING_TABLE = { - (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', - (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', - (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', - (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', - (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', - (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', - (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', - (byte) '7', (byte) '8', (byte) '9', - (byte) '+', (byte) '/' - }; - - /** - * The padding byte. - */ - private static final byte PADDING = (byte) '='; - - /** - * Set up the decoding table; this is indexed by a byte converted to an unsigned int, - * so must be at least as large as the number of different byte values, - * positive and negative and zero. - */ - private static final byte[] DECODING_TABLE = new byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1]; - - static { - // Initialize as all invalid characters - Arrays.fill(DECODING_TABLE, INVALID_BYTE); - // set up valid characters - for (int i = 0; i < ENCODING_TABLE.length; i++) { - DECODING_TABLE[ENCODING_TABLE[i]] = (byte) i; - } - // Allow pad byte to be easily detected after conversion - DECODING_TABLE[PADDING] = PAD_BYTE; - } - - /** - * Hidden constructor, this class must not be instantiated. - */ - private Base64Decoder() { - // do nothing - } - - /** - * Decode the base 64 encoded byte data writing it to the given output stream, - * whitespace characters will be ignored. - * - * @param data the buffer containing the Base64-encoded data - * @param out the output stream to hold the decoded bytes - * @return the number of bytes produced. - * @throws IOException thrown when the padding is incorrect or the input is truncated. - */ - public static int decode(final byte[] data, final OutputStream out) throws IOException { - int outLen = 0; - final byte[] cache = new byte[INPUT_BYTES_PER_CHUNK]; - int cachedBytes = 0; - - for (final byte b : data) { - final byte d = DECODING_TABLE[MASK_BYTE_UNSIGNED & b]; - if (d == INVALID_BYTE) { - continue; // Ignore invalid bytes - } - cache[cachedBytes++] = d; - if (cachedBytes == INPUT_BYTES_PER_CHUNK) { - // CHECKSTYLE IGNORE MagicNumber FOR NEXT 4 LINES - final byte b1 = cache[0]; - final byte b2 = cache[1]; - final byte b3 = cache[2]; - final byte b4 = cache[3]; - if (b1 == PAD_BYTE || b2 == PAD_BYTE) { - throw new IOException("Invalid Base64 input: incorrect padding, first two bytes cannot be padding"); - } - // Convert 4 6-bit bytes to 3 8-bit bytes - // CHECKSTYLE IGNORE MagicNumber FOR NEXT 1 LINE - out.write((b1 << 2) | (b2 >> 4)); // 6 bits of b1 plus 2 bits of b2 - outLen++; - if (b3 != PAD_BYTE) { - // CHECKSTYLE IGNORE MagicNumber FOR NEXT 1 LINE - out.write((b2 << 4) | (b3 >> 2)); // 4 bits of b2 plus 4 bits of b3 - outLen++; - if (b4 != PAD_BYTE) { - // CHECKSTYLE IGNORE MagicNumber FOR NEXT 1 LINE - out.write((b3 << 6) | b4); // 2 bits of b3 plus 6 bits of b4 - outLen++; - } - } else if (b4 != PAD_BYTE) { // if byte 3 is pad, byte 4 must be pad too - throw new // line wrap to avoid 120 char limit - IOException("Invalid Base64 input: incorrect padding, 4th byte must be padding if 3rd byte is"); - } - cachedBytes = 0; - } - } - // Check for anything left over - if (cachedBytes != 0) { - throw new IOException("Invalid Base64 input: truncated"); - } - return outLen; - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java b/client/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java deleted file mode 100644 index 847ea415af..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/mime/MimeUtility.java +++ /dev/null @@ -1,274 +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.commons.fileupload2.util.mime; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -/** - * Utility class to decode MIME texts. - * - * @since 1.3 - */ -public final class MimeUtility { - - /** - * The marker to indicate text is encoded with BASE64 algorithm. - */ - private static final String BASE64_ENCODING_MARKER = "B"; - - /** - * The marker to indicate text is encoded with QuotedPrintable algorithm. - */ - private static final String QUOTEDPRINTABLE_ENCODING_MARKER = "Q"; - - /** - * If the text contains any encoded tokens, those tokens will be marked with "=?". - */ - private static final String ENCODED_TOKEN_MARKER = "=?"; - - /** - * If the text contains any encoded tokens, those tokens will terminate with "=?". - */ - private static final String ENCODED_TOKEN_FINISHER = "?="; - - /** - * The linear whitespace chars sequence. - */ - private static final String LINEAR_WHITESPACE = " \t\r\n"; - - /** - * Mappings between MIME and Java charset. - */ - private static final Map MIME2JAVA = new HashMap<>(); - - static { - MIME2JAVA.put("iso-2022-cn", "ISO2022CN"); - MIME2JAVA.put("iso-2022-kr", "ISO2022KR"); - MIME2JAVA.put("utf-8", "UTF8"); - MIME2JAVA.put("utf8", "UTF8"); - MIME2JAVA.put("ja_jp.iso2022-7", "ISO2022JP"); - MIME2JAVA.put("ja_jp.eucjp", "EUCJIS"); - MIME2JAVA.put("euc-kr", "KSC5601"); - MIME2JAVA.put("euckr", "KSC5601"); - MIME2JAVA.put("us-ascii", "ISO-8859-1"); - MIME2JAVA.put("x-us-ascii", "ISO-8859-1"); - } - - /** - * Hidden constructor, this class must not be instantiated. - */ - private MimeUtility() { - // do nothing - } - - /** - * Decode a string of text obtained from a mail header into - * its proper form. The text generally will consist of a - * string of tokens, some of which may be encoded using - * base64 encoding. - * - * @param text The text to decode. - * @return The decoded text string. - * @throws UnsupportedEncodingException if the detected encoding in the input text is not supported. - */ - public static String decodeText(final String text) throws UnsupportedEncodingException { - // if the text contains any encoded tokens, those tokens will be marked with "=?". If the - // source string doesn't contain that sequent, no decoding is required. - if (!text.contains(ENCODED_TOKEN_MARKER)) { - return text; - } - - int offset = 0; - final int endOffset = text.length(); - - int startWhiteSpace = -1; - int endWhiteSpace = -1; - - final StringBuilder decodedText = new StringBuilder(text.length()); - - boolean previousTokenEncoded = false; - - while (offset < endOffset) { - char ch = text.charAt(offset); - - // is this a whitespace character? - if (LINEAR_WHITESPACE.indexOf(ch) != -1) { // whitespace found - startWhiteSpace = offset; - while (offset < endOffset) { - // step over the white space characters. - ch = text.charAt(offset); - if (LINEAR_WHITESPACE.indexOf(ch) == -1) { - // record the location of the first non lwsp and drop down to process the - // token characters. - endWhiteSpace = offset; - break; - } - offset++; - } - } else { - // we have a word token. We need to scan over the word and then try to parse it. - final int wordStart = offset; - - while (offset < endOffset) { - // step over the non white space characters. - ch = text.charAt(offset); - if (LINEAR_WHITESPACE.indexOf(ch) != -1) { - break; - } - offset++; - - //NB: Trailing whitespace on these header strings will just be discarded. - } - // pull out the word token. - final String word = text.substring(wordStart, offset); - // is the token encoded? decode the word - if (word.startsWith(ENCODED_TOKEN_MARKER)) { - try { - // if this gives a parsing failure, treat it like a non-encoded word. - final String decodedWord = decodeWord(word); - - // are any whitespace characters significant? Append 'em if we've got 'em. - if (!previousTokenEncoded && startWhiteSpace != -1) { - decodedText.append(text, startWhiteSpace, endWhiteSpace); - startWhiteSpace = -1; - } - // this is definitely a decoded token. - previousTokenEncoded = true; - // and add this to the text. - decodedText.append(decodedWord); - // we continue parsing from here...we allow parsing errors to fall through - // and get handled as normal text. - continue; - - } catch (final ParseException e) { - // just ignore it, skip to next word - } - } - // this is a normal token, so it doesn't matter what the previous token was. Add the white space - // if we have it. - if (startWhiteSpace != -1) { - decodedText.append(text, startWhiteSpace, endWhiteSpace); - startWhiteSpace = -1; - } - // this is not a decoded token. - previousTokenEncoded = false; - decodedText.append(word); - } - } - - return decodedText.toString(); - } - - /** - * Parse a string using the RFC 2047 rules for an "encoded-word" - * type. This encoding has the syntax: - *

- * encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" - * - * @param word The possibly encoded word value. - * @return The decoded word. - * @throws ParseException in case of a parse error of the RFC 2047 - * @throws UnsupportedEncodingException Thrown when Invalid RFC 2047 encoding was found - */ - private static String decodeWord(final String word) throws ParseException, UnsupportedEncodingException { - // encoded words start with the characters "=?". If this not an encoded word, we throw a - // ParseException for the caller. - - if (!word.startsWith(ENCODED_TOKEN_MARKER)) { - throw new ParseException("Invalid RFC 2047 encoded-word: " + word); - } - - final int charsetPos = word.indexOf('?', 2); - if (charsetPos == -1) { - throw new ParseException("Missing charset in RFC 2047 encoded-word: " + word); - } - - // pull out the character set information (this is the MIME name at this point). - final String charset = word.substring(2, charsetPos).toLowerCase(Locale.ENGLISH); - - // now pull out the encoding token the same way. - final int encodingPos = word.indexOf('?', charsetPos + 1); - if (encodingPos == -1) { - throw new ParseException("Missing encoding in RFC 2047 encoded-word: " + word); - } - - final String encoding = word.substring(charsetPos + 1, encodingPos); - - // and finally the encoded text. - final int encodedTextPos = word.indexOf(ENCODED_TOKEN_FINISHER, encodingPos + 1); - if (encodedTextPos == -1) { - throw new ParseException("Missing encoded text in RFC 2047 encoded-word: " + word); - } - - final String encodedText = word.substring(encodingPos + 1, encodedTextPos); - - // seems a bit silly to encode a null string, but easy to deal with. - if (encodedText.isEmpty()) { - return ""; - } - - try { - // the decoder writes directly to an output stream. - final ByteArrayOutputStream out = new ByteArrayOutputStream(encodedText.length()); - - final byte[] encodedData = encodedText.getBytes(StandardCharsets.US_ASCII); - - // Base64 encoded? - if (encoding.equals(BASE64_ENCODING_MARKER)) { - Base64Decoder.decode(encodedData, out); - } else if (encoding.equals(QUOTEDPRINTABLE_ENCODING_MARKER)) { // maybe quoted printable. - QuotedPrintableDecoder.decode(encodedData, out); - } else { - throw new UnsupportedEncodingException("Unknown RFC 2047 encoding: " + encoding); - } - // get the decoded byte data and convert into a string. - final byte[] decodedData = out.toByteArray(); - return new String(decodedData, javaCharset(charset)); - } catch (final IOException e) { - throw new UnsupportedEncodingException("Invalid RFC 2047 encoding"); - } - } - - /** - * Translate a MIME standard character set name into the Java - * equivalent. - * - * @param charset The MIME standard name. - * @return The Java equivalent for this name. - */ - private static String javaCharset(final String charset) { - // nothing in, nothing out. - if (charset == null) { - return null; - } - - final String mappedCharset = MIME2JAVA.get(charset.toLowerCase(Locale.ENGLISH)); - // if there is no mapping, then the original name is used. Many of the MIME character set - // names map directly back into Java. The reverse isn't necessarily true. - if (mappedCharset == null) { - return charset; - } - return mappedCharset; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/mime/ParseException.java b/client/src/test/java/org/apache/commons/fileupload2/util/mime/ParseException.java deleted file mode 100644 index 7981ea4907..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/mime/ParseException.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.commons.fileupload2.util.mime; - -/** - * @since 1.3 - */ -final class ParseException extends Exception { - - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = 5355281266579392077L; - - /** - * Constructs a new exception with the specified detail message. - * - * @param message the detail message. - */ - ParseException(final String message) { - super(message); - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java b/client/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java deleted file mode 100644 index 88c0270b46..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/mime/QuotedPrintableDecoder.java +++ /dev/null @@ -1,111 +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.commons.fileupload2.util.mime; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * @since 1.3 - */ -final class QuotedPrintableDecoder { - - /** - * The shift value required to create the upper nibble - * from the first of 2 byte values converted from ascii hex. - */ - private static final int UPPER_NIBBLE_SHIFT = Byte.SIZE / 2; - - /** - * Hidden constructor, this class must not be instantiated. - */ - private QuotedPrintableDecoder() { - // do nothing - } - - /** - * Decode the encoded byte data writing it to the given output stream. - * - * @param data The array of byte data to decode. - * @param out The output stream used to return the decoded data. - * @return the number of bytes produced. - * @throws IOException if an IO error occurs - */ - public static int decode(final byte[] data, final OutputStream out) throws IOException { - int off = 0; - final int length = data.length; - final int endOffset = off + length; - int bytesWritten = 0; - - while (off < endOffset) { - final byte ch = data[off++]; - - // space characters were translated to '_' on encode, so we need to translate them back. - if (ch == '_') { - out.write(' '); - } else if (ch == '=') { - // we found an encoded character. Reduce the 3 char sequence to one. - // but first, make sure we have two characters to work with. - if (off + 1 >= endOffset) { - throw new IOException("Invalid quoted printable encoding; truncated escape sequence"); - } - - final byte b1 = data[off++]; - final byte b2 = data[off++]; - - // we've found an encoded carriage return. The next char needs to be a newline - if (b1 == '\r') { - if (b2 != '\n') { - throw new IOException("Invalid quoted printable encoding; CR must be followed by LF"); - } - // this was a soft linebreak inserted by the encoding. We just toss this away - // on decode. - } else { - // this is a hex pair we need to convert back to a single byte. - final int c1 = hexToBinary(b1); - final int c2 = hexToBinary(b2); - out.write((c1 << UPPER_NIBBLE_SHIFT) | c2); - // 3 bytes in, one byte out - bytesWritten++; - } - } else { - // simple character, just write it out. - out.write(ch); - bytesWritten++; - } - } - - return bytesWritten; - } - - /** - * Convert a hex digit to the binary value it represents. - * - * @param b the ascii hex byte to convert (0-0, A-F, a-f) - * @return the int value of the hex byte, 0-15 - * @throws IOException if the byte is not a valid hex digit. - */ - private static int hexToBinary(final byte b) throws IOException { - // CHECKSTYLE IGNORE MagicNumber FOR NEXT 1 LINE - final int i = Character.digit((char) b, 16); - if (i == -1) { - throw new IOException("Invalid quoted printable encoding: not a valid hex digit: " + b); - } - return i; - } - -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java b/client/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java deleted file mode 100644 index 4033765197..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/mime/RFC2231Utility.java +++ /dev/null @@ -1,160 +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.commons.fileupload2.util.mime; - -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; - -/** - * Utility class to decode/encode character set on HTTP Header fields based on RFC 2231. - * This implementation adheres to RFC 5987 in particular, which was defined for HTTP headers - *

- * RFC 5987 builds on RFC 2231, but has lesser scope like - * mandatory charset definition - * and no parameter continuation - * - *

- * - * @see RFC 2231 - * @see RFC 5987 - */ -public final class RFC2231Utility { - /** - * The Hexadecimal values char array. - */ - private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); - /** - * The Hexadecimal representation of 127. - */ - private static final byte MASK = 0x7f; - /** - * The Hexadecimal representation of 128. - */ - private static final int MASK_128 = 0x80; - /** - * The Hexadecimal decode value. - */ - private static final byte[] HEX_DECODE = new byte[MASK_128]; - - // create a ASCII decoded array of Hexadecimal values - static { - for (int i = 0; i < HEX_DIGITS.length; i++) { - HEX_DECODE[HEX_DIGITS[i]] = (byte) i; - HEX_DECODE[Character.toLowerCase(HEX_DIGITS[i])] = (byte) i; - } - } - - /** - * Private constructor so that no instances can be created. This class - * contains only static utility methods. - */ - private RFC2231Utility() { - } - - /** - * Checks if Asterisk (*) at the end of parameter name to indicate, - * if it has charset and language information to decode the value. - * - * @param paramName The parameter, which is being checked. - * @return {@code true}, if encoded as per RFC 2231, {@code false} otherwise - */ - public static boolean hasEncodedValue(final String paramName) { - if (paramName != null) { - return paramName.lastIndexOf('*') == (paramName.length() - 1); - } - return false; - } - - /** - * If {@code paramName} has Asterisk (*) at the end, it will be stripped off, - * else the passed value will be returned. - * - * @param paramName The parameter, which is being inspected. - * @return stripped {@code paramName} of Asterisk (*), if RFC2231 encoded - */ - public static String stripDelimiter(final String paramName) { - if (hasEncodedValue(paramName)) { - final StringBuilder paramBuilder = new StringBuilder(paramName); - paramBuilder.deleteCharAt(paramName.lastIndexOf('*')); - return paramBuilder.toString(); - } - return paramName; - } - - /** - * Decode a string of text obtained from a HTTP header as per RFC 2231 - * - * Eg 1. {@code us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A} - * will be decoded to {@code This is ***fun***} - * - * Eg 2. {@code iso-8859-1'en'%A3%20rate} - * will be decoded to {@code £ rate}. - * - * Eg 3. {@code UTF-8''%c2%a3%20and%20%e2%82%ac%20rates} - * will be decoded to {@code £ and € rates}. - * - * @param encodedText - Text to be decoded has a format of {@code ''} - * and ASCII only - * @return Decoded text based on charset encoding - * @throws UnsupportedEncodingException The requested character set wasn't found. - */ - public static String decodeText(final String encodedText) throws UnsupportedEncodingException { - final int langDelimitStart = encodedText.indexOf('\''); - if (langDelimitStart == -1) { - // missing charset - return encodedText; - } - final String mimeCharset = encodedText.substring(0, langDelimitStart); - final int langDelimitEnd = encodedText.indexOf('\'', langDelimitStart + 1); - if (langDelimitEnd == -1) { - // missing language - return encodedText; - } - final byte[] bytes = fromHex(encodedText.substring(langDelimitEnd + 1)); - return new String(bytes, getJavaCharset(mimeCharset)); - } - - /** - * Convert {@code text} to their corresponding Hex value. - * - * @param text - ASCII text input - * @return Byte array of characters decoded from ASCII table - */ - private static byte[] fromHex(final String text) { - final int shift = 4; - final ByteArrayOutputStream out = new ByteArrayOutputStream(text.length()); - for (int i = 0; i < text.length(); ) { - final char c = text.charAt(i++); - if (c == '%') { - if (i > text.length() - 2) { - break; // unterminated sequence - } - final byte b1 = HEX_DECODE[text.charAt(i++) & MASK]; - final byte b2 = HEX_DECODE[text.charAt(i++) & MASK]; - out.write((b1 << shift) | b2); - } else { - out.write((byte) c); - } - } - return out.toByteArray(); - } - - private static String getJavaCharset(final String mimeCharset) { - // good enough for standard values - return mimeCharset; - } -} diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/mime/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/util/mime/package-info.java deleted file mode 100644 index 6b9c410d33..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/mime/package-info.java +++ /dev/null @@ -1,22 +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. - */ - -/** - * MIME decoder implementation, imported and retailed from - * Apache Geronimo. - */ -package org.apache.commons.fileupload2.util.mime; diff --git a/client/src/test/java/org/apache/commons/fileupload2/util/package-info.java b/client/src/test/java/org/apache/commons/fileupload2/util/package-info.java deleted file mode 100644 index 95817a14a7..0000000000 --- a/client/src/test/java/org/apache/commons/fileupload2/util/package-info.java +++ /dev/null @@ -1,23 +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. - */ - -/** - * This package contains various IO related utility classes - * or methods, which are basically reusable and not necessarily - * restricted to the scope of a file upload. - */ -package org.apache.commons.fileupload2.util; diff --git a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java index 4a79e52dce..695f6c1a06 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java @@ -16,11 +16,10 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.apache.commons.fileupload2.FileItemIterator; -import org.apache.commons.fileupload2.FileItemStream; -import org.apache.commons.fileupload2.FileUploadException; -import org.apache.commons.fileupload2.jaksrvlt.JakSrvltFileUpload; -import org.apache.commons.fileupload2.util.Streams; +import org.apache.commons.fileupload2.core.FileItemInput; +import org.apache.commons.fileupload2.core.FileItemInputIterator; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.asynchttpclient.AbstractBasicTest; @@ -372,21 +371,21 @@ public int getStringsProcessed() { @Override public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { // Check that we have a file upload request - boolean isMultipart = JakSrvltFileUpload.isMultipartContent(request); + boolean isMultipart = JakartaServletFileUpload.isMultipartContent(request); if (isMultipart) { List files = new ArrayList<>(); - JakSrvltFileUpload upload = new JakSrvltFileUpload(); + JakartaServletFileUpload upload = new JakartaServletFileUpload(); // Parse the request - FileItemIterator iter; + FileItemInputIterator iter; try { iter = upload.getItemIterator(request); while (iter.hasNext()) { - FileItemStream item = iter.next(); + FileItemInput item = iter.next(); String name = item.getFieldName(); - try (InputStream stream = item.openStream()) { + try (InputStream stream = item.getInputStream()) { if (item.isFormField()) { - LOGGER.debug("Form field " + name + " with value " + Streams.asString(stream) + " detected."); + LOGGER.debug("Form field " + name + " with value " + IOUtils.toString(stream, UTF_8) + " detected."); incrementStringsProcessed(); } else { LOGGER.debug("File field " + name + " with file name " + item.getName() + " detected.");