This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-fileupload.git
commit 9c0e80624af5ba1ed8e46e959c07ff8070f2f0b1 Author: Gary D. Gregory <garydgreg...@gmail.com> AuthorDate: Tue Sep 9 07:57:24 2025 -0700 Sort members --- .../fileupload2/core/AbstractFileUpload.java | 134 ++++++------ .../fileupload2/core/DeferrableOutputStream.java | 234 ++++++++++----------- .../commons/fileupload2/core/DiskFileItem.java | 130 ++++++------ .../fileupload2/core/DiskFileItemFactory.java | 64 +++--- .../core/DeferrableOutputStreamTest.java | 96 ++++----- .../commons/fileupload2/core/DiskFileItemTest.java | 140 ++++++------ 6 files changed, 399 insertions(+), 399 deletions(-) diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/AbstractFileUpload.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/AbstractFileUpload.java index fc81b7ec..e0c1f503 100644 --- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/AbstractFileUpload.java +++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/AbstractFileUpload.java @@ -207,15 +207,6 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil return fieldName; } - /** - * Gets the maximum number of files allowed in a single request. - * - * @return The maximum number of files allowed in a single request. - */ - public long getMaxFileCount() { - return maxFileCount; - } - /** * Gets the factory class used when creating file items. * @@ -266,16 +257,6 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil return fileName; } - /** - * Gets the maximum allowed size of a single uploaded file, as opposed to {@link #getMaxSize()}. - * - * @see #setMaxFileSize(long) - * @return Maximum size of a single uploaded file. - */ - public long getMaxFileSize() { - return maxFileSize; - } - /** * Gets 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. @@ -310,6 +291,46 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil return new FileItemInputIteratorImpl(this, requestContext); } + /** + * Gets the maximum number of files allowed in a single request. + * + * @return The maximum number of files allowed in a single request. + */ + public long getMaxFileCount() { + return maxFileCount; + } + + /** + * Gets the maximum allowed size of a single uploaded file, as opposed to {@link #getMaxSize()}. + * + * @see #setMaxFileSize(long) + * @return Maximum size of a single uploaded file. + */ + public long getMaxFileSize() { + return maxFileSize; + } + + /** + * Gets the per part size limit for headers. + * + * @return The maximum size of the headers for a single part in bytes. + * + * @since 2.0.0-M5 + */ + public int getMaxPartHeaderSize() { + return maxPartHeaderSize; + } + + /** + * Gets the maximum allowed size of a complete request, as opposed to {@link #getMaxFileSize()}. + * + * @return The maximum allowed size, in bytes. The default value of -1 indicates, that there is no limit. + * @see #setMaxSize(long) + */ + public long getMaxSize() { + return maxSize; + } + /** * Parses the {@code header-part} and returns as key/value pairs. * <p> @@ -352,17 +373,6 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil return headers; } - /** - * Gets the per part size limit for headers. - * - * @return The maximum size of the headers for a single part in bytes. - * - * @since 2.0.0-M5 - */ - public int getMaxPartHeaderSize() { - return maxPartHeaderSize; - } - /** * Gets the progress listener. * @@ -372,16 +382,6 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil return progressListener; } - /** - * Gets the maximum allowed size of a complete request, as opposed to {@link #getMaxFileSize()}. - * - * @return The maximum allowed size, in bytes. The default value of -1 indicates, that there is no limit. - * @see #setMaxSize(long) - */ - public long getMaxSize() { - return maxSize; - } - /** * Creates a new instance of {@link FileItemHeaders}. * @@ -527,41 +527,41 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil } /** - * Sets the maximum number of files allowed per request. + * Sets the factory class to use when creating file items. * - * @param fileCountMax The new limit. {@code -1} means no limit. + * @param factory The factory class for new file items. */ - public void setMaxFileCount(final long fileCountMax) { - this.maxFileCount = fileCountMax; + public void setFileItemFactory(final F factory) { + this.fileItemFactory = factory; } /** - * Sets the factory class to use when creating file items. + * 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 factory The factory class for new file items. + * @param headerCharset The encoding used to read part headers. */ - public void setFileItemFactory(final F factory) { - this.fileItemFactory = factory; + public void setHeaderCharset(final Charset headerCharset) { + this.headerCharset = headerCharset; } /** - * Sets the maximum allowed size of a single uploaded file, as opposed to {@link #getMaxSize()}. + * Sets the maximum number of files allowed per request. * - * @see #getMaxFileSize() - * @param fileSizeMax Maximum size of a single uploaded file. + * @param fileCountMax The new limit. {@code -1} means no limit. */ - public void setMaxFileSize(final long fileSizeMax) { - this.maxFileSize = fileSizeMax; + public void setMaxFileCount(final long fileCountMax) { + this.maxFileCount = fileCountMax; } /** - * 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. + * Sets the maximum allowed size of a single uploaded file, as opposed to {@link #getMaxSize()}. * - * @param headerCharset The encoding used to read part headers. + * @see #getMaxFileSize() + * @param fileSizeMax Maximum size of a single uploaded file. */ - public void setHeaderCharset(final Charset headerCharset) { - this.headerCharset = headerCharset; + public void setMaxFileSize(final long fileSizeMax) { + this.maxFileSize = fileSizeMax; } /** @@ -575,15 +575,6 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil this.maxPartHeaderSize = partHeaderSizeMax; } - /** - * Sets the progress listener. - * - * @param progressListener The progress listener, if any. Defaults to null. - */ - public void setProgressListener(final ProgressListener progressListener) { - this.progressListener = progressListener != null ? progressListener : ProgressListener.NOP; - } - /** * Sets the maximum allowed size of a complete request, as opposed to {@link #setMaxFileSize(long)}. * @@ -594,4 +585,13 @@ public abstract class AbstractFileUpload<R, I extends FileItem<I>, F extends Fil this.maxSize = sizeMax; } + /** + * Sets the progress listener. + * + * @param progressListener The progress listener, if any. Defaults to null. + */ + public void setProgressListener(final ProgressListener progressListener) { + this.progressListener = progressListener != null ? progressListener : ProgressListener.NOP; + } + } diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DeferrableOutputStream.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DeferrableOutputStream.java index 73c49622..c2a13abb 100644 --- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DeferrableOutputStream.java +++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DeferrableOutputStream.java @@ -59,6 +59,18 @@ import java.util.function.Supplier; * <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-295</a>) */ public class DeferrableOutputStream extends OutputStream { + /** Interface of a listener object, that wishes to be notified about + * state changes. + */ + public interface Listener { + /** Called, after {@link #persist()} has been invoked, + * and the temporary file has been created. + * @param path Path of the temporary file, that has been + * created. All in-memory data has been transferred to + * that file, but it is still opened. + */ + default void persisted(final Path path) { } + } /** This enumeration represents the possible states of the {@link DeferrableOutputStream}. */ public enum State { @@ -87,18 +99,6 @@ public class DeferrableOutputStream extends OutputStream { */ closed } - /** Interface of a listener object, that wishes to be notified about - * state changes. - */ - public interface Listener { - /** Called, after {@link #persist()} has been invoked, - * and the temporary file has been created. - * @param path Path of the temporary file, that has been - * created. All in-memory data has been transferred to - * that file, but it is still opened. - */ - default void persisted(final Path path) { } - } /** The configured threshold, as an integer. This variable isn't actually * used. Instead {@link #longThreshold} is used. * @see #longThreshold @@ -181,13 +181,6 @@ public class DeferrableOutputStream extends OutputStream { checkThreshold(0); } - /** Returns the streams configured threshold. - * @return The streams configured threshold. - */ - public int getThreshold() { - return threshold; - } - /** Called to check, whether the threshold will be exceeded, if the given number * of bytes are written to the stream. If so, persists the in-memory data by * creating a new, temporary file, and writing the in-memory data to the file. @@ -234,66 +227,6 @@ public class DeferrableOutputStream extends OutputStream { } } - /** Create the output file, change the state to {@code persisted}, and - * return an {@link OutputStream}, which is writing to that file. - * @return The {@link OutputStream}, which is writing to the created, - * temporary file. - * @throws IOException Creating the temporary file has failed. - */ - protected OutputStream persist() throws IOException { - final Path p = pathSupplier.get(); - final Path dir = p.getParent(); - if (dir != null) { - Files.createDirectories(dir); - } - final OutputStream os = Files.newOutputStream(p); - if (baos != null) { - baos.writeTo(os); - } - /** At this point, the output file has been successfully created, - * and we can safely switch state. - */ - state = State.persisted; - wasPersisted = true; - path = p; - out = os; - baos = null; - bytes = null; - if (listener != null) { - listener.persisted(p); - } - return os; - } - - @Override - public void write(final int b) throws IOException { - final OutputStream os = checkThreshold(1); - if (os == null) { - throw new IOException("This stream has already been closed."); - } - bytes = null; - os.write(b); - size++; - } - - @Override - public void write(final byte[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - @Override - public void write(final byte[] buffer, final int offset, final int len) throws IOException { - if (len > 0) { - final OutputStream os = checkThreshold(len); - if (os == null) { - throw new IOException("This stream has already been closed."); - } - bytes = null; - os.write(buffer, offset, len); - size += len; - } - } - @Override public void close() throws IOException { switch (state) { @@ -316,40 +249,6 @@ public class DeferrableOutputStream extends OutputStream { } } - /** Returns true, if this stream was never persisted, - * and no output file has been created. - * @return True, if the stream was never in state - * {@link State#persisted}, otherwise false. - */ - public boolean isInMemory() { - switch (state) { - case initialized: - case opened: - return true; - case persisted: - return false; - case closed: - return !wasPersisted; - default: - throw illegalStateError(); - } - } - - /** Returns the streams current state. - * @return The streams current state. - */ - public State getState() { - return state; - } - - /** Returns the output file, that has been created, if any, or null. - * The latter is the case, if {@link #isInMemory()} returns true. - * @return The output file, that has been created, if any, or null. - */ - public Path getPath() { - return path; - } - /** Returns the data, that has been written, if the stream has * been closed, and the stream is still in memory * ({@link #isInMemory()} returns true). Otherwise, returns null. @@ -384,6 +283,35 @@ public class DeferrableOutputStream extends OutputStream { } } + /** Returns the output file, that has been created, if any, or null. + * The latter is the case, if {@link #isInMemory()} returns true. + * @return The output file, that has been created, if any, or null. + */ + public Path getPath() { + return path; + } + + /** Returns the number of bytes, that have been written to this stream. + * @return The number of bytes, that have been written to this stream. + */ + public long getSize() { + return size; + } + + /** Returns the streams current state. + * @return The streams current state. + */ + public State getState() { + return state; + } + + /** Returns the streams configured threshold. + * @return The streams configured threshold. + */ + public int getThreshold() { + return threshold; + } + /** Returns the path of the output file, if such a file has * been created. That is the case, if {@link #isInMemory()} * returns false. Otherwise, returns null. @@ -393,10 +321,82 @@ public class DeferrableOutputStream extends OutputStream { throw new IllegalStateException("Expected state initialized|opened|persisted|closed, got " + state.name()); } - /** Returns the number of bytes, that have been written to this stream. - * @return The number of bytes, that have been written to this stream. + /** Returns true, if this stream was never persisted, + * and no output file has been created. + * @return True, if the stream was never in state + * {@link State#persisted}, otherwise false. */ - public long getSize() { - return size; + public boolean isInMemory() { + switch (state) { + case initialized: + case opened: + return true; + case persisted: + return false; + case closed: + return !wasPersisted; + default: + throw illegalStateError(); + } + } + + /** Create the output file, change the state to {@code persisted}, and + * return an {@link OutputStream}, which is writing to that file. + * @return The {@link OutputStream}, which is writing to the created, + * temporary file. + * @throws IOException Creating the temporary file has failed. + */ + protected OutputStream persist() throws IOException { + final Path p = pathSupplier.get(); + final Path dir = p.getParent(); + if (dir != null) { + Files.createDirectories(dir); + } + final OutputStream os = Files.newOutputStream(p); + if (baos != null) { + baos.writeTo(os); + } + /** At this point, the output file has been successfully created, + * and we can safely switch state. + */ + state = State.persisted; + wasPersisted = true; + path = p; + out = os; + baos = null; + bytes = null; + if (listener != null) { + listener.persisted(p); + } + return os; + } + + @Override + public void write(final byte[] buffer) throws IOException { + write(buffer, 0, buffer.length); + } + + @Override + public void write(final byte[] buffer, final int offset, final int len) throws IOException { + if (len > 0) { + final OutputStream os = checkThreshold(len); + if (os == null) { + throw new IOException("This stream has already been closed."); + } + bytes = null; + os.write(buffer, offset, len); + size += len; + } + } + + @Override + public void write(final int b) throws IOException { + final OutputStream os = checkThreshold(1); + if (os == null) { + throw new IOException("This stream has already been closed."); + } + bytes = null; + os.write(b); + size++; } } diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItem.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItem.java index 19e17f84..88c509f4 100644 --- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItem.java +++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItem.java @@ -108,6 +108,11 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { */ public static class Builder extends AbstractFileItemBuilder<DiskFileItem, Builder> { + /** The threshold. We do maintain this separate from the {@link #getBufferSize()}, + * because the parent class might change the value in {@link #setBufferSize(int)}. + */ + private int threshold; + /** * Constructs a new instance. */ @@ -140,21 +145,13 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return diskFileItem; } - /** The threshold. We do maintain this separate from the {@link #getBufferSize()}, - * because the parent class might change the value in {@link #setBufferSize(int)}. - */ - private int threshold; - - /** Sets the threshold. The uploaded data is typically kept in memory, until - * a certain number of bytes (the threshold) is reached. At this point, the - * incoming data is transferred to a temporary file, and the in-memory data - * is removed. - * @param threshold The threshold, which is being used. - * @return This builder. + /** Equivalent to {@link #getThreshold()}. + * @return The threshold, which is being used. + * @see #getThreshold() + * @deprecated Since 2.0.0, use {@link #getThreshold()} instead. */ - public Builder setThreshold(final int threshold) { - this.threshold = threshold; - return this; + public int getBufferSize() { + return getThreshold(); } /** Returns the threshold. @@ -175,13 +172,16 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return setThreshold(bufferSize); } - /** Equivalent to {@link #getThreshold()}. - * @return The threshold, which is being used. - * @see #getThreshold() - * @deprecated Since 2.0.0, use {@link #getThreshold()} instead. + /** Sets the threshold. The uploaded data is typically kept in memory, until + * a certain number of bytes (the threshold) is reached. At this point, the + * incoming data is transferred to a temporary file, and the in-memory data + * is removed. + * @param threshold The threshold, which is being used. + * @return This builder. */ - public int getBufferSize() { - return getThreshold(); + public Builder setThreshold(final int threshold) { + this.threshold = threshold; + return this; } } @@ -335,24 +335,6 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { this.repository = repository != null ? repository : PathUtils.getTempDirectory(); } - /** Sets the {@link FileCleaningTracker}, which is being used to remove - * temporary files. - * @param fileCleaningTracker The {@link FileCleaningTracker}, which is being used to - * remove temporary files. - */ - public void setFileCleaningTracker(final FileCleaningTracker fileCleaningTracker) { - this.fileCleaningTracker = fileCleaningTracker; - } - - /** Returns the {@link FileCleaningTracker}, which is being used to remove - * temporary files. - * @return The {@link FileCleaningTracker}, which is being used to remove - * temporary files. - */ - public FileCleaningTracker getFileCleaningTracker() { - return fileCleaningTracker; - } - /** * 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. @@ -439,6 +421,15 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return fieldName; } + /** Returns the {@link FileCleaningTracker}, which is being used to remove + * temporary files. + * @return The {@link FileCleaningTracker}, which is being used to remove + * temporary files. + */ + public FileCleaningTracker getFileCleaningTracker() { + return fileCleaningTracker; + } + /** * Gets the file item headers. * @@ -519,6 +510,26 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return null; } + /** Returns the contents of the file as a {@link Reader}, using the specified + * {@link #getCharset()}. If the contents are not yet available, returns null. + * This is the case, for example, if the underlying output stream has not yet + * been closed. + * @return The contents of the file as a {@link Reader} + * @throws UnsupportedEncodingException The chararacter set, which is + * specified in the files "content-type" header, is invalid. + * @throws IOException An I/O error occurred, while the + * underlying {@link #getInputStream() input stream} was created. + */ + public Reader getReader() throws IOException, UnsupportedEncodingException { + final InputStream is = getInputStream(); + final var parser = new ParameterParser(); + parser.setLowerCaseNames(true); + // Parameter parser can handle null input + final var params = parser.parse(getContentType(), ';'); + final Charset cs = Charsets.toCharset(params.get("charset"), charsetDefault); + return new InputStreamReader(is, cs); + } + /** * Gets the size of the file. * @@ -552,26 +563,6 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return new String(bytes, getCharset()); } - /** Returns the contents of the file as a {@link Reader}, using the specified - * {@link #getCharset()}. If the contents are not yet available, returns null. - * This is the case, for example, if the underlying output stream has not yet - * been closed. - * @return The contents of the file as a {@link Reader} - * @throws UnsupportedEncodingException The chararacter set, which is - * specified in the files "content-type" header, is invalid. - * @throws IOException An I/O error occurred, while the - * underlying {@link #getInputStream() input stream} was created. - */ - public Reader getReader() throws IOException, UnsupportedEncodingException { - final InputStream is = getInputStream(); - final var parser = new ParameterParser(); - parser.setLowerCaseNames(true); - // Parameter parser can handle null input - final var params = parser.parse(getContentType(), ';'); - final Charset cs = Charsets.toCharset(params.get("charset"), charsetDefault); - return new InputStreamReader(is, cs); - } - /** * Gets the contents of the file as a String, using the specified encoding. This method uses {@link #get()} to retrieve the contents of the file. * @@ -584,6 +575,13 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return new String(get(), Charsets.toCharset(charset, charsetDefault)); } + /** Returns the file items threshold. + * @return The threshold. + */ + public int getThreshold() { + return threshold; + } + /** * Tests whether or not a {@code FileItem} instance represents a simple form field. * @@ -631,6 +629,15 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { return this; } + /** Sets the {@link FileCleaningTracker}, which is being used to remove + * temporary files. + * @param fileCleaningTracker The {@link FileCleaningTracker}, which is being used to + * remove temporary files. + */ + public void setFileCleaningTracker(final FileCleaningTracker fileCleaningTracker) { + this.fileCleaningTracker = fileCleaningTracker; + } + /** * Specifies whether or not a {@code FileItem} instance represents a simple form field. * @@ -706,11 +713,4 @@ public final class DiskFileItem implements FileItem<DiskFileItem> { } return this; } - - /** Returns the file items threshold. - * @return The threshold. - */ - public int getThreshold() { - return threshold; - } } diff --git a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItemFactory.java b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItemFactory.java index f61e4540..08f42e45 100644 --- a/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItemFactory.java +++ b/commons-fileupload2-core/src/main/java/org/apache/commons/fileupload2/core/DiskFileItemFactory.java @@ -82,6 +82,11 @@ public final class DiskFileItemFactory implements FileItemFactory<DiskFileItem> */ private FileCleaningTracker fileCleaningTracker; + /** The threshold. We do maintain this separate from the {@link #getBufferSize()}, + * because the parent class might change the value in {@link #setBufferSize(int)}. + */ + private int threshold; + /** * Constructs a new instance. */ @@ -111,6 +116,33 @@ public final class DiskFileItemFactory implements FileItemFactory<DiskFileItem> return new DiskFileItemFactory(getPath(), getBufferSize(), getCharset(), fileCleaningTracker); } + /** Equivalent to {@link #getThreshold()}. + * @return The threshold, which is being used. + * @see #getThreshold() + * @deprecated Since 2.0.0, use {@link #getThreshold()} instead. + */ + public int getBufferSize() { + return getThreshold(); + } + + /** Returns the threshold. + * @return The threshold. + */ + public int getThreshold() { + return threshold; + } + + /** Eqivalent to {@link #setThreshold(int)}. + * @param bufferSize The threshold, which is being used. + * @see #setThreshold(int) + * @return This builder. + * @deprecated Since 2.0.0, use {@link #setThreshold(int)} instead. + */ + @Override + public Builder setBufferSize(final int bufferSize) { + return setThreshold(bufferSize); + } + /** * Sets the tracker, which is responsible for deleting temporary files. * @@ -122,11 +154,6 @@ public final class DiskFileItemFactory implements FileItemFactory<DiskFileItem> return this; } - /** The threshold. We do maintain this separate from the {@link #getBufferSize()}, - * because the parent class might change the value in {@link #setBufferSize(int)}. - */ - private int threshold; - /** Sets the threshold. The uploaded data is typically kept in memory, until * a certain number of bytes (the threshold) is reached. At this point, the * incoming data is transferred to a temporary file, and the in-memory data @@ -142,33 +169,6 @@ public final class DiskFileItemFactory implements FileItemFactory<DiskFileItem> this.threshold = threshold; return this; } - - /** Returns the threshold. - * @return The threshold. - */ - public int getThreshold() { - return threshold; - } - - /** Eqivalent to {@link #setThreshold(int)}. - * @param bufferSize The threshold, which is being used. - * @see #setThreshold(int) - * @return This builder. - * @deprecated Since 2.0.0, use {@link #setThreshold(int)} instead. - */ - @Override - public Builder setBufferSize(final int bufferSize) { - return setThreshold(bufferSize); - } - - /** Equivalent to {@link #getThreshold()}. - * @return The threshold, which is being used. - * @see #getThreshold() - * @deprecated Since 2.0.0, use {@link #getThreshold()} instead. - */ - public int getBufferSize() { - return getThreshold(); - } } /** diff --git a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DeferrableOutputStreamTest.java b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DeferrableOutputStreamTest.java index 7b94a86b..d90fc272 100644 --- a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DeferrableOutputStreamTest.java +++ b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DeferrableOutputStreamTest.java @@ -41,6 +41,12 @@ import org.apache.commons.fileupload2.core.DeferrableOutputStream.State; class DeferrableOutputStreamTest { private static final Path testDir = Paths.get("target/unit-tests/DeferrableOutputStreamTest"); private static Path tempTestDir; + @BeforeAll + static void setUpTestDirs() throws IOException { + Files.createDirectories(testDir); + tempTestDir = Files.createTempDirectory(testDir, "testDir"); + } + private Supplier<Path> testFileSupplier = () -> { try { return Files.createTempFile(tempTestDir, "testFile", ".bin"); @@ -49,10 +55,17 @@ class DeferrableOutputStreamTest { } }; - @BeforeAll - static void setUpTestDirs() throws IOException { - Files.createDirectories(testDir); - tempTestDir = Files.createTempDirectory(testDir, "testDir"); + protected byte[] read(InputStream pIs) throws IOException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final byte[] buffer = new byte[8192]; + for (;;) { + final int res = pIs.read(buffer); + if (res == -1) { + return baos.toByteArray(); + } else if (res > 0) { + baos.write(buffer, 0, res); + } + } } /** Tests using the {@link DeferrableOutputStream} with a positive threshold. @@ -128,6 +141,37 @@ class DeferrableOutputStreamTest { }); } + /** Tests using the {@link DeferrableOutputStream} with threshold -1. + */ + @Test + void testThresholdMinusOne() { + DeferrableOutputStream[] streams = new DeferrableOutputStream[1]; + final Runnable tester = () -> { + try (final DeferrableOutputStream dos = new DeferrableOutputStream(-1, testFileSupplier, null)) { + streams[0] = dos; + assertFalse(dos.isInMemory()); + assertNotNull(dos.getPath()); + assertNull(dos.getBytes()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + + final DeferrableOutputStream dos = streams[0]; + assertFalse(dos.isInMemory()); + assertNotNull(dos.getPath()); + assertTrue(Files.isRegularFile(dos.getPath())); + final byte[] actual; + try (InputStream is = dos.getInputStream()) { + actual = read(is); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + final byte[] expect = "".getBytes(StandardCharsets.UTF_8); + assertArrayEquals(expect, actual); + }; + tester.run(); + } + /** Tests using the {@link DeferrableOutputStream} with threshold 0. */ @Test @@ -188,48 +232,4 @@ class DeferrableOutputStreamTest { } }); } - - /** Tests using the {@link DeferrableOutputStream} with threshold -1. - */ - @Test - void testThresholdMinusOne() { - DeferrableOutputStream[] streams = new DeferrableOutputStream[1]; - final Runnable tester = () -> { - try (final DeferrableOutputStream dos = new DeferrableOutputStream(-1, testFileSupplier, null)) { - streams[0] = dos; - assertFalse(dos.isInMemory()); - assertNotNull(dos.getPath()); - assertNull(dos.getBytes()); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - - final DeferrableOutputStream dos = streams[0]; - assertFalse(dos.isInMemory()); - assertNotNull(dos.getPath()); - assertTrue(Files.isRegularFile(dos.getPath())); - final byte[] actual; - try (InputStream is = dos.getInputStream()) { - actual = read(is); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - final byte[] expect = "".getBytes(StandardCharsets.UTF_8); - assertArrayEquals(expect, actual); - }; - tester.run(); - } - - protected byte[] read(InputStream pIs) throws IOException { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final byte[] buffer = new byte[8192]; - for (;;) { - final int res = pIs.read(buffer); - if (res == -1) { - return baos.toByteArray(); - } else if (res > 0) { - baos.write(buffer, 0, res); - } - } - } } diff --git a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DiskFileItemTest.java b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DiskFileItemTest.java index 064146a3..d46c3801 100644 --- a/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DiskFileItemTest.java +++ b/commons-fileupload2-core/src/test/java/org/apache/commons/fileupload2/core/DiskFileItemTest.java @@ -42,6 +42,29 @@ import org.junit.jupiter.api.Test; * Tests for {@link DiskFileItem}. */ class DiskFileItemTest { + @SuppressWarnings("deprecation") + protected void assertState(final DiskFileItem dfi, final State state, final boolean inMemory, final Path parentDir, String testString) throws IOException { + final DeferrableOutputStream dos = (DeferrableOutputStream) dfi.getOutputStream(); + assertEquals(state, dos.getState()); + assertEquals(inMemory, dfi.isInMemory()); + assertEquals(inMemory, dos.isInMemory()); + if (parentDir == null) { + assertNull(dos.getPath()); + } else { + assertNotNull(dos.getPath()); + assertEquals(parentDir, dos.getPath().getParent()); + } + if (testString != null) { + assertEquals(testString.length(), dfi.getSize()); + assertEquals(testString.length(), dos.getSize()); + assertEquals(testString, dfi.getString()); + assertArrayEquals(testString.getBytes(), dfi.get()); + } else { + assertNull(dfi.get()); + assertNull(dfi.getString()); + } + } + @Test void testBuilderHeaders() { final var builder = DiskFileItem.builder(); @@ -57,120 +80,120 @@ class DiskFileItemTest { } /** Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-29</a>: - * A {@link #DiskFileItem} with threshold -1 must always create a (possibly empty) file. + * A {@link #DiskFileItem} with threshold 0 must always create a file, as soon as data comes in. */ @Test - void testStateModelWithThresholdMinusOne() { - final Consumer<String> tester = (ts) -> { + void testStateModelWithPositiveThreshold() { + final IntConsumer tester = (numBytes) -> { try { final Path testDir = Paths.get("target/unit-tests/" + DiskFileItemTest.class.getSimpleName()); Files.createDirectories(testDir); final Path tempTestDir = Files.createTempDirectory(testDir, "testDir"); final DiskFileItemFactory dfif = DiskFileItemFactory.builder() - .setBufferSize(-1) + .setThreshold(numBytes) .setPath(tempTestDir) .setCharset(StandardCharsets.UTF_8) .get(); - // Make sure, that the threshold has not been tampered with. - assertEquals(-1, dfif.getThreshold()); + assertEquals(numBytes, dfif.getThreshold()); final DiskFileItem dfi = dfif.fileItemBuilder() .get(); // Make sure, that the threshold has not been tampered with. - assertEquals(-1, dfi.getThreshold()); - // We haven't written any data. Yet, the output file already exists (threshold=-1) - assertState(dfi, State.persisted, false, tempTestDir, null); - try (OutputStream out = dfi.getOutputStream()) { - out.write(ts.getBytes()); + assertEquals(numBytes, dfi.getThreshold()); + // We haven't written any data. So, the output file is null. + assertState(dfi, State.initialized, true, null, null); + // Write some data. + final StringBuilder sb = new StringBuilder(); + try (OutputStream os = dfi.getOutputStream()) { + for (int i = 0; i < numBytes-1; i++) { + os.write('.'); + sb.append('.'); + assertState(dfi, State.opened, true, null, null); + } + /** Write another byte. This should hit the threshold, + * thus trigger persisting the in memory data. + */ + os.write(','); + sb.append(','); + assertState(dfi, State.persisted, false, tempTestDir, null); } - // After writing some data, the output file does still exist, except that the size has changed. - assertState(dfi, State.closed, false, tempTestDir, ts); + // The output stream is closed now, so the state has changed again. + assertState(dfi, State.closed, false, tempTestDir, sb.toString()); } catch (IOException ioe) { throw new UncheckedIOException(ioe); } }; - tester.accept("abcdef"); - tester.accept("aAbBcCdDeEfF012345"); + tester.accept(5); + tester.accept(8193); // Typical buffer size +1 } /** Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-29</a>: - * A {@link #DiskFileItem} with threshold 0 must always create a file, as soon as data comes in. + * A {@link #DiskFileItem} with threshold -1 must always create a (possibly empty) file. */ @Test - void testStateModelWithThresholdZero() { - final IntConsumer tester = (numBytes) -> { + void testStateModelWithThresholdMinusOne() { + final Consumer<String> tester = (ts) -> { try { final Path testDir = Paths.get("target/unit-tests/" + DiskFileItemTest.class.getSimpleName()); Files.createDirectories(testDir); final Path tempTestDir = Files.createTempDirectory(testDir, "testDir"); final DiskFileItemFactory dfif = DiskFileItemFactory.builder() - .setBufferSize(0) + .setBufferSize(-1) .setPath(tempTestDir) .setCharset(StandardCharsets.UTF_8) .get(); - assertEquals(0, dfif.getThreshold()); + // Make sure, that the threshold has not been tampered with. + assertEquals(-1, dfif.getThreshold()); final DiskFileItem dfi = dfif.fileItemBuilder() .get(); // Make sure, that the threshold has not been tampered with. - assertEquals(0, dfi.getThreshold()); - // We haven't written any data. So, the output file is null. - assertState(dfi, State.initialized, true, null, null); - // Write some data. - final StringBuilder sb = new StringBuilder(); - try (OutputStream os = dfi.getOutputStream()) { - for (int i = 0; i < numBytes; i++) { - os.write('.'); - sb.append('.'); - assertState(dfi, State.persisted, false, tempTestDir, null); - } - os.write(','); - sb.append(','); + assertEquals(-1, dfi.getThreshold()); + // We haven't written any data. Yet, the output file already exists (threshold=-1) + assertState(dfi, State.persisted, false, tempTestDir, null); + try (OutputStream out = dfi.getOutputStream()) { + out.write(ts.getBytes()); } - // The output stream is closed now, so the state has changed again. - assertState(dfi, State.closed, false, tempTestDir, sb.toString()); + // After writing some data, the output file does still exist, except that the size has changed. + assertState(dfi, State.closed, false, tempTestDir, ts); } catch (IOException ioe) { throw new UncheckedIOException(ioe); } }; - tester.accept(5); - tester.accept(8193); // Typical buffer size +1 + tester.accept("abcdef"); + tester.accept("aAbBcCdDeEfF012345"); } /** Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-29</a>: * A {@link #DiskFileItem} with threshold 0 must always create a file, as soon as data comes in. */ @Test - void testStateModelWithPositiveThreshold() { + void testStateModelWithThresholdZero() { final IntConsumer tester = (numBytes) -> { try { final Path testDir = Paths.get("target/unit-tests/" + DiskFileItemTest.class.getSimpleName()); Files.createDirectories(testDir); final Path tempTestDir = Files.createTempDirectory(testDir, "testDir"); final DiskFileItemFactory dfif = DiskFileItemFactory.builder() - .setThreshold(numBytes) + .setBufferSize(0) .setPath(tempTestDir) .setCharset(StandardCharsets.UTF_8) .get(); - assertEquals(numBytes, dfif.getThreshold()); + assertEquals(0, dfif.getThreshold()); final DiskFileItem dfi = dfif.fileItemBuilder() .get(); // Make sure, that the threshold has not been tampered with. - assertEquals(numBytes, dfi.getThreshold()); + assertEquals(0, dfi.getThreshold()); // We haven't written any data. So, the output file is null. assertState(dfi, State.initialized, true, null, null); // Write some data. final StringBuilder sb = new StringBuilder(); try (OutputStream os = dfi.getOutputStream()) { - for (int i = 0; i < numBytes-1; i++) { + for (int i = 0; i < numBytes; i++) { os.write('.'); sb.append('.'); - assertState(dfi, State.opened, true, null, null); + assertState(dfi, State.persisted, false, tempTestDir, null); } - /** Write another byte. This should hit the threshold, - * thus trigger persisting the in memory data. - */ os.write(','); sb.append(','); - assertState(dfi, State.persisted, false, tempTestDir, null); } // The output stream is closed now, so the state has changed again. assertState(dfi, State.closed, false, tempTestDir, sb.toString()); @@ -181,27 +204,4 @@ class DiskFileItemTest { tester.accept(5); tester.accept(8193); // Typical buffer size +1 } - - @SuppressWarnings("deprecation") - protected void assertState(final DiskFileItem dfi, final State state, final boolean inMemory, final Path parentDir, String testString) throws IOException { - final DeferrableOutputStream dos = (DeferrableOutputStream) dfi.getOutputStream(); - assertEquals(state, dos.getState()); - assertEquals(inMemory, dfi.isInMemory()); - assertEquals(inMemory, dos.isInMemory()); - if (parentDir == null) { - assertNull(dos.getPath()); - } else { - assertNotNull(dos.getPath()); - assertEquals(parentDir, dos.getPath().getParent()); - } - if (testString != null) { - assertEquals(testString.length(), dfi.getSize()); - assertEquals(testString.length(), dos.getSize()); - assertEquals(testString, dfi.getString()); - assertArrayEquals(testString.getBytes(), dfi.get()); - } else { - assertNull(dfi.get()); - assertNull(dfi.getString()); - } - } } \ No newline at end of file