You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/12/07 17:14:03 UTC

[tomcat] branch 8.5.x updated (98fd719 -> 1f9d3e6)

This is an automated email from the ASF dual-hosted git repository.

markt pushed a change to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git.


    from 98fd719  BZ 63982: CombinedRealm makes assumptions about principal implementation
     new 5d4e832  Merge in BCEL changes to ff6941e (2019-12-06, 6.4.2-dev)
     new 99382b7  Merge in Codec changes to 9637dd4 (2019-12-06, 1.14-SNAPSHOT)
     new 218ea93  Merge in FileUpload changes to 2317552 (2019-12-06, 2.0-SNAPSHOT)
     new a3fd9ee  Merge in Pool 2 changes to 6092f92 (2019-12-06, 2.8.0-SNAPSHOT)
     new 1706b31  Merge in DBCP 2 changes 2 a363390 (2019-12-06, 2.7.1-SNAPSHOT)
     new b9469e8  Fix Findbugs warnings
     new b167af1  Remove unused code reported by SpotBugs
     new 1a5e42b  Fix FileUpload
     new b8d9fbc  Fix codec
     new 17ffce9  Clean-up. No functional change.
     new 38ec82c  Clean-up prior to some refactoring.
     new 0fded7d  Refactor change of session ID to reduce duplicate code
     new e19a202  Refactor so Principal is never cached in session with cache==false
     new e8ae801  Harden the FORM authentication process
     new 6dcf03e  Add an atomic method to rotate session ID and return new value. Use it.
     new 98c7c55  Update changelog
     new d9a1db7  Fix back-port of atomic session ID rotation. Replace default method.
     new 1f9d3e6  Refactor wait to make test failure due to timing issues less likely

The 18 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 MERGE.txt                                          |   20 +-
 .../catalina/authenticator/AuthenticatorBase.java  |   36 +-
 .../apache/catalina/authenticator/Constants.java   |   51 +-
 .../catalina/authenticator/FormAuthenticator.java  |  107 +-
 java/org/apache/catalina/connector/Request.java    |   34 +-
 java/org/apache/catalina/session/ManagerBase.java  |    6 +
 .../apache/tomcat/dbcp/dbcp2/AbandonedTrace.java   |   92 +-
 .../dbcp/pool2/BaseKeyedPooledObjectFactory.java   |    2 +
 .../apache/tomcat/dbcp/pool2/BaseObjectPool.java   |   18 +
 .../apache/tomcat/dbcp/pool2/KeyedObjectPool.java  |  211 ++--
 java/org/apache/tomcat/dbcp/pool2/ObjectPool.java  |  134 ++-
 java/org/apache/tomcat/dbcp/pool2/PoolUtils.java   | 1270 ++------------------
 .../org/apache/tomcat/dbcp/pool2/PooledObject.java |    3 +-
 .../dbcp/pool2/impl/DefaultEvictionPolicy.java     |    2 +
 .../tomcat/dbcp/pool2/impl/EvictionConfig.java     |    1 +
 .../dbcp/pool2/impl/GenericKeyedObjectPool.java    |   78 +-
 .../tomcat/dbcp/pool2/impl/GenericObjectPool.java  |   46 +-
 .../pool2/impl/InterruptibleReentrantLock.java     |    1 +
 .../dbcp/pool2/impl/LinkedBlockingDeque.java       |    4 +
 .../dbcp/pool2/impl/SoftReferenceObjectPool.java   |    3 +
 java/org/apache/tomcat/util/bcel/Const.java        |   14 +-
 .../tomcat/util/bcel/classfile/ConstantClass.java  |    2 +-
 .../tomcat/util/bcel/classfile/ConstantDouble.java |    2 +-
 .../tomcat/util/bcel/classfile/ConstantFloat.java  |    2 +-
 .../util/bcel/classfile/ConstantInteger.java       |    2 +-
 .../tomcat/util/bcel/classfile/ConstantLong.java   |    2 +-
 .../apache/tomcat/util/codec/binary/Base64.java    |   28 +-
 .../tomcat/util/codec/binary/BaseNCodec.java       |  100 +-
 .../util/http/fileupload/FileItemIterator.java     |   49 +-
 .../util/http/fileupload/FileUploadBase.java       |  702 +----------
 .../util/http/fileupload/MultipartStream.java      |   10 +-
 .../util/http/fileupload/disk/DiskFileItem.java    |    3 +-
 .../http/fileupload/impl/FileItemIteratorImpl.java |  339 ++++++
 .../http/fileupload/impl/FileItemStreamImpl.java   |  213 ++++
 .../impl/FileSizeLimitExceededException.java       |   94 ++
 .../fileupload/impl/FileUploadIOException.java     |   63 +
 .../fileupload/impl/IOFileUploadException.java     |   62 +
 .../impl/InvalidContentTypeException.java          |   62 +
 .../util/http/fileupload/impl/SizeException.java   |   75 ++
 .../SizeLimitExceededException.java}               |   25 +-
 .../authenticator/TestBasicAuthParser.java         |   15 +-
 .../org/apache/catalina/session/FileStoreTest.java |   12 +-
 test/org/apache/tomcat/util/net/TestSsl.java       |   29 +-
 webapps/docs/changelog.xml                         |   25 +
 44 files changed, 1738 insertions(+), 2311 deletions(-)
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java
 create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
 copy java/org/apache/tomcat/util/http/fileupload/{util/mime/ParseException.java => impl/SizeLimitExceededException.java} (53%)


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 04/18: Merge in Pool 2 changes to 6092f92 (2019-12-06, 2.8.0-SNAPSHOT)

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit a3fd9eee952b99974b23f0b328f5fb3f25f79c5e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 15:43:08 2019 +0000

    Merge in Pool 2 changes to 6092f92 (2019-12-06, 2.8.0-SNAPSHOT)
---
 MERGE.txt                                          |   12 +-
 .../dbcp/pool2/BaseKeyedPooledObjectFactory.java   |    2 +
 .../apache/tomcat/dbcp/pool2/BaseObjectPool.java   |   18 +
 .../apache/tomcat/dbcp/pool2/KeyedObjectPool.java  |  211 ++--
 java/org/apache/tomcat/dbcp/pool2/ObjectPool.java  |  134 ++-
 java/org/apache/tomcat/dbcp/pool2/PoolUtils.java   | 1270 ++------------------
 .../org/apache/tomcat/dbcp/pool2/PooledObject.java |    3 +-
 .../dbcp/pool2/impl/DefaultEvictionPolicy.java     |    2 +
 .../tomcat/dbcp/pool2/impl/EvictionConfig.java     |    1 +
 .../dbcp/pool2/impl/GenericKeyedObjectPool.java    |   78 +-
 .../tomcat/dbcp/pool2/impl/GenericObjectPool.java  |   46 +-
 .../pool2/impl/InterruptibleReentrantLock.java     |    1 +
 .../dbcp/pool2/impl/LinkedBlockingDeque.java       |    4 +
 .../dbcp/pool2/impl/SoftReferenceObjectPool.java   |    3 +
 webapps/docs/changelog.xml                         |    4 +
 15 files changed, 421 insertions(+), 1368 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index 893ac89..7daec6d 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -58,15 +58,15 @@ Note: Tomcat's copy of fileupload also includes classes copied manually from
 
 DBCP
 ----
+Pool2
+Sub-tree
+src/main/java/org/apache/commons/pool2
+The SHA1 ID for the most recent commit to be merged to Tomcat is:
+6092f924b36061353ff92b18c88400ab3bc05327 (2019-12-06)
+
 DBCP2
 Sub-tree
 src/main/java/org/apache/commons/dbcp2
 src/main/resources/org/apache/commons/dbcp2
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
 4813b7f5456c1f4fecc4f701ac731a71f57db249 (2019-08-09)
-
-Pool2
-Sub-tree
-src/main/java/org/apache/commons/pool2
-The SHA1 ID for the most recent commit to be merged to Tomcat is:
-796e32d53cc0d870ba0db3a7faf4c5b24ff76f3f (2019-08-01)
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
index 3dd7429..dfbc5a9 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
@@ -21,7 +21,9 @@ package org.apache.tomcat.dbcp.pool2;
  * <p>
  * All operations defined here are essentially no-op's.
  * </p>
+ * <p>
  * This class is immutable, and therefore thread-safe.
+ * </p>
  *
  * @see KeyedPooledObjectFactory
  *
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
index 29f189a..96d3c00 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
@@ -22,6 +22,7 @@ package org.apache.tomcat.dbcp.pool2;
  * indicating it is unsupported or throw {@link UnsupportedOperationException}.
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @param <T> Type of element pooled in this pool.
  *
@@ -82,6 +83,23 @@ public abstract class BaseObjectPool<T> extends BaseObject implements ObjectPool
     }
 
     /**
+     * Calls {@link ObjectPool#addObject()} <code>count</code>
+     * number of times.
+     *
+     * @param count
+     *            the number of idle objects to add.
+     * @throws Exception
+     *             when {@link ObjectPool#addObject()} fails.
+     * @since 2.8.0
+     */
+    @Override
+    public void addObjects(final int count) throws Exception {
+        for (int i = 0; i < count; i++) {
+            addObject();
+        }
+    }
+
+    /**
      * {@inheritDoc}
      * <p>
      * This affects the behavior of <code>isClosed</code> and
diff --git a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
index 4df37d8..df325ed 100644
--- a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
@@ -17,6 +17,7 @@
 package org.apache.tomcat.dbcp.pool2;
 
 import java.io.Closeable;
+import java.util.Collection;
 import java.util.NoSuchElementException;
 
 /**
@@ -66,6 +67,60 @@ import java.util.NoSuchElementException;
  * @since 2.0
  */
 public interface KeyedObjectPool<K, V> extends Closeable {
+
+    /**
+     * Create an object using the {@link KeyedPooledObjectFactory factory} or
+     * other implementation dependent mechanism, passivate it, and then place it
+     * in the idle object pool. <code>addObject</code> is useful for
+     * "pre-loading" a pool with idle objects (Optional operation).
+     *
+     * @param key the key a new instance should be added to
+     *
+     * @throws Exception
+     *              when {@link KeyedPooledObjectFactory#makeObject} fails.
+     * @throws IllegalStateException
+     *              after {@link #close} has been called on this pool.
+     * @throws UnsupportedOperationException
+     *              when this pool cannot add new idle objects.
+     */
+    void addObject(K key) throws Exception, IllegalStateException,
+            UnsupportedOperationException;
+
+    /**
+     * Calls {@link KeyedObjectPool#addObject(Object)} with each
+     * key in <code>keys</code> for <code>count</code> number of times. This has
+     * the same effect as calling {@link #addObjects(Object, int)}
+     * for each key in the <code>keys</code> collection.
+     *
+     * @param keys
+     *            {@link Collection} of keys to add objects for.
+     * @param count
+     *            the number of idle objects to add for each <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>keyedPool</code>, <code>keys</code>, or any value
+     *             in <code>keys</code> is <code>null</code>.
+     * @see #addObjects(Object, int)
+     */
+    void addObjects(final Collection<K> keys, final int count) throws Exception, IllegalArgumentException;
+
+    /**
+     * Calls {@link KeyedObjectPool#addObject(Object)}
+     * <code>key</code> <code>count</code> number of times.
+     *
+     * @param key
+     *            the key to add objects for.
+     * @param count
+     *            the number of idle objects to add for <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>key</code> is <code>null</code>.
+     * @since 2.8.0
+     */
+    void addObjects(final K key, final int count) throws Exception, IllegalArgumentException;
+
     /**
      * Obtains an instance from this pool for the specified <code>key</code>.
      * <p>
@@ -105,75 +160,50 @@ public interface KeyedObjectPool<K, V> extends Closeable {
     V borrowObject(K key) throws Exception, NoSuchElementException, IllegalStateException;
 
     /**
-     * Return an instance to the pool. By contract, <code>obj</code>
-     * <strong>must</strong> have been obtained using
-     * {@link #borrowObject borrowObject} or a related method as defined in an
-     * implementation or sub-interface using a <code>key</code> that is
-     * equivalent to the one used to borrow the instance in the first place.
-     *
-     * @param key the key used to obtain the object
-     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     * Clears the pool, removing all pooled instances (optional operation).
      *
-     * @throws IllegalStateException
-     *              if an attempt is made to return an object to the pool that
-     *              is in any state other than allocated (i.e. borrowed).
-     *              Attempting to return an object more than once or attempting
-     *              to return an object that was never borrowed from the pool
-     *              will trigger this exception.
+     * @throws UnsupportedOperationException when this implementation doesn't
+     *                                       support the operation
      *
-     * @throws Exception if an instance cannot be returned to the pool
+     * @throws Exception if the pool cannot be cleared
      */
-    void returnObject(K key, V obj) throws Exception;
+    void clear() throws Exception, UnsupportedOperationException;
 
     /**
-     * Invalidates an object from the pool.
-     * <p>
-     * By contract, <code>obj</code> <strong>must</strong> have been obtained
-     * using {@link #borrowObject borrowObject} or a related method as defined
-     * in an implementation or sub-interface using a <code>key</code> that is
-     * equivalent to the one used to borrow the <code>Object</code> in the first
-     * place.
-     * </p>
-     * <p>
-     * This method should be used when an object that has been borrowed is
-     * determined (due to an exception or other problem) to be invalid.
-     * </p>
+     * Clears the specified pool, removing all pooled instances corresponding to
+     * the given <code>key</code> (optional operation).
      *
-     * @param key the key used to obtain the object
-     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     * @param key the key to clear
      *
-     * @throws Exception if the instance cannot be invalidated
+     * @throws UnsupportedOperationException when this implementation doesn't
+     *                                       support the operation
+     *
+     * @throws Exception if the key cannot be cleared
      */
-    void invalidateObject(K key, V obj) throws Exception;
+    void clear(K key) throws Exception, UnsupportedOperationException;
 
     /**
-     * Create an object using the {@link KeyedPooledObjectFactory factory} or
-     * other implementation dependent mechanism, passivate it, and then place it
-     * in the idle object pool. <code>addObject</code> is useful for
-     * "pre-loading" a pool with idle objects (Optional operation).
-     *
-     * @param key the key a new instance should be added to
-     *
-     * @throws Exception
-     *              when {@link KeyedPooledObjectFactory#makeObject} fails.
-     * @throws IllegalStateException
-     *              after {@link #close} has been called on this pool.
-     * @throws UnsupportedOperationException
-     *              when this pool cannot add new idle objects.
+     * Close this pool, and free any resources associated with it.
+     * <p>
+     * Calling {@link #addObject addObject} or
+     * {@link #borrowObject borrowObject} after invoking this method on a pool
+     * will cause them to throw an {@link IllegalStateException}.
+     * </p>
+     * <p>
+     * Implementations should silently fail if not all resources can be freed.
+     * </p>
      */
-    void addObject(K key) throws Exception, IllegalStateException,
-            UnsupportedOperationException;
+    @Override
+    void close();
 
     /**
-     * Returns the number of instances corresponding to the given
-     * <code>key</code> currently idle in this pool. Returns a negative value if
-     * this information is not available.
-     *
-     * @param key the key to query
-     * @return the number of instances corresponding to the given
-     * <code>key</code> currently idle in this pool.
+     * Returns the total number of instances currently borrowed from this pool but
+     * not yet returned. Returns a negative value if this information is not
+     * available.
+     * @return the total number of instances currently borrowed from this pool but
+     * not yet returned.
      */
-    int getNumIdle(K key);
+    int getNumActive();
 
     /**
      * Returns the number of instances currently borrowed from but not yet
@@ -194,48 +224,55 @@ public interface KeyedObjectPool<K, V> extends Closeable {
     int getNumIdle();
 
     /**
-     * Returns the total number of instances currently borrowed from this pool but
-     * not yet returned. Returns a negative value if this information is not
-     * available.
-     * @return the total number of instances currently borrowed from this pool but
-     * not yet returned.
+     * Returns the number of instances corresponding to the given
+     * <code>key</code> currently idle in this pool. Returns a negative value if
+     * this information is not available.
+     *
+     * @param key the key to query
+     * @return the number of instances corresponding to the given
+     * <code>key</code> currently idle in this pool.
      */
-    int getNumActive();
+    int getNumIdle(K key);
 
     /**
-     * Clears the pool, removing all pooled instances (optional operation).
+     * Invalidates an object from the pool.
+     * <p>
+     * By contract, <code>obj</code> <strong>must</strong> have been obtained
+     * using {@link #borrowObject borrowObject} or a related method as defined
+     * in an implementation or sub-interface using a <code>key</code> that is
+     * equivalent to the one used to borrow the <code>Object</code> in the first
+     * place.
+     * </p>
+     * <p>
+     * This method should be used when an object that has been borrowed is
+     * determined (due to an exception or other problem) to be invalid.
+     * </p>
      *
-     * @throws UnsupportedOperationException when this implementation doesn't
-     *                                       support the operation
+     * @param key the key used to obtain the object
+     * @param obj a {@link #borrowObject borrowed} instance to be returned.
      *
-     * @throws Exception if the pool cannot be cleared
+     * @throws Exception if the instance cannot be invalidated
      */
-    void clear() throws Exception, UnsupportedOperationException;
+    void invalidateObject(K key, V obj) throws Exception;
 
     /**
-     * Clears the specified pool, removing all pooled instances corresponding to
-     * the given <code>key</code> (optional operation).
+     * Return an instance to the pool. By contract, <code>obj</code>
+     * <strong>must</strong> have been obtained using
+     * {@link #borrowObject borrowObject} or a related method as defined in an
+     * implementation or sub-interface using a <code>key</code> that is
+     * equivalent to the one used to borrow the instance in the first place.
      *
-     * @param key the key to clear
+     * @param key the key used to obtain the object
+     * @param obj a {@link #borrowObject borrowed} instance to be returned.
      *
-     * @throws UnsupportedOperationException when this implementation doesn't
-     *                                       support the operation
+     * @throws IllegalStateException
+     *              if an attempt is made to return an object to the pool that
+     *              is in any state other than allocated (i.e. borrowed).
+     *              Attempting to return an object more than once or attempting
+     *              to return an object that was never borrowed from the pool
+     *              will trigger this exception.
      *
-     * @throws Exception if the key cannot be cleared
-     */
-    void clear(K key) throws Exception, UnsupportedOperationException;
-
-    /**
-     * Close this pool, and free any resources associated with it.
-     * <p>
-     * Calling {@link #addObject addObject} or
-     * {@link #borrowObject borrowObject} after invoking this method on a pool
-     * will cause them to throw an {@link IllegalStateException}.
-     * </p>
-     * <p>
-     * Implementations should silently fail if not all resources can be freed.
-     * </p>
+     * @throws Exception if an instance cannot be returned to the pool
      */
-    @Override
-    void close();
+    void returnObject(K key, V obj) throws Exception;
 }
diff --git a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
index 6303245..22eb12a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
@@ -60,6 +60,34 @@ import java.util.NoSuchElementException;
 public interface ObjectPool<T> extends Closeable {
 
     /**
+     * Creates an object using the {@link PooledObjectFactory factory} or other
+     * implementation dependent mechanism, passivate it, and then place it in
+     * the idle object pool. <code>addObject</code> is useful for "pre-loading"
+     * a pool with idle objects. (Optional operation).
+     *
+     * @throws Exception
+     *              when {@link PooledObjectFactory#makeObject} fails.
+     * @throws IllegalStateException
+     *              after {@link #close} has been called on this pool.
+     * @throws UnsupportedOperationException
+     *              when this pool cannot add new idle objects.
+     */
+    void addObject() throws Exception, IllegalStateException,
+            UnsupportedOperationException;
+
+    /**
+     * Calls {@link ObjectPool#addObject()} <code>count</code>
+     * number of times.
+     *
+     * @param count
+     *            the number of idle objects to add.
+     * @throws Exception
+     *             when {@link ObjectPool#addObject()} fails.
+     * @since 2.8.0
+     */
+    void addObjects(final int count) throws Exception;
+
+    /**
      * Obtains an instance from this pool.
      * <p>
      * Instances returned from this method will have been either newly created
@@ -94,56 +122,36 @@ public interface ObjectPool<T> extends Closeable {
             IllegalStateException;
 
     /**
-     * Returns an instance to the pool. By contract, <code>obj</code>
-     * <strong>must</strong> have been obtained using {@link #borrowObject()} or
-     * a related method as defined in an implementation or sub-interface.
-     *
-     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     * Clears any objects sitting idle in the pool, releasing any associated
+     * resources (optional operation). Idle objects cleared must be
+     * {@link PooledObjectFactory#destroyObject(PooledObject)}.
      *
-     * @throws IllegalStateException
-     *              if an attempt is made to return an object to the pool that
-     *              is in any state other than allocated (i.e. borrowed).
-     *              Attempting to return an object more than once or attempting
-     *              to return an object that was never borrowed from the pool
-     *              will trigger this exception.
+     * @throws UnsupportedOperationException
+     *              if this implementation does not support the operation
      *
-     * @throws Exception if an instance cannot be returned to the pool
+     * @throws Exception if the pool cannot be cleared
      */
-    void returnObject(T obj) throws Exception;
+    void clear() throws Exception, UnsupportedOperationException;
 
     /**
-     * Invalidates an object from the pool.
+     * Closes this pool, and free any resources associated with it.
      * <p>
-     * By contract, <code>obj</code> <strong>must</strong> have been obtained
-     * using {@link #borrowObject} or a related method as defined in an
-     * implementation or sub-interface.
+     * Calling {@link #addObject} or {@link #borrowObject} after invoking this
+     * method on a pool will cause them to throw an {@link IllegalStateException}.
      * </p>
      * <p>
-     * This method should be used when an object that has been borrowed is
-     * determined (due to an exception or other problem) to be invalid.
+     * Implementations should silently fail if not all resources can be freed.
      * </p>
-     *
-     * @param obj a {@link #borrowObject borrowed} instance to be disposed.
-     *
-     * @throws Exception if the instance cannot be invalidated
      */
-    void invalidateObject(T obj) throws Exception;
+    @Override
+    void close();
 
     /**
-     * Creates an object using the {@link PooledObjectFactory factory} or other
-     * implementation dependent mechanism, passivate it, and then place it in
-     * the idle object pool. <code>addObject</code> is useful for "pre-loading"
-     * a pool with idle objects. (Optional operation).
-     *
-     * @throws Exception
-     *              when {@link PooledObjectFactory#makeObject} fails.
-     * @throws IllegalStateException
-     *              after {@link #close} has been called on this pool.
-     * @throws UnsupportedOperationException
-     *              when this pool cannot add new idle objects.
+     * Returns the number of instances currently borrowed from this pool. Returns
+     * a negative value if this information is not available.
+     * @return the number of instances currently borrowed from this pool.
      */
-    void addObject() throws Exception, IllegalStateException,
-            UnsupportedOperationException;
+    int getNumActive();
 
     /**
      * Returns the number of instances currently idle in this pool. This may be
@@ -155,34 +163,38 @@ public interface ObjectPool<T> extends Closeable {
     int getNumIdle();
 
     /**
-     * Returns the number of instances currently borrowed from this pool. Returns
-     * a negative value if this information is not available.
-     * @return the number of instances currently borrowed from this pool.
-     */
-    int getNumActive();
-
-    /**
-     * Clears any objects sitting idle in the pool, releasing any associated
-     * resources (optional operation). Idle objects cleared must be
-     * {@link PooledObjectFactory#destroyObject(PooledObject)}.
+     * Invalidates an object from the pool.
+     * <p>
+     * By contract, <code>obj</code> <strong>must</strong> have been obtained
+     * using {@link #borrowObject} or a related method as defined in an
+     * implementation or sub-interface.
+     * </p>
+     * <p>
+     * This method should be used when an object that has been borrowed is
+     * determined (due to an exception or other problem) to be invalid.
+     * </p>
      *
-     * @throws UnsupportedOperationException
-     *              if this implementation does not support the operation
+     * @param obj a {@link #borrowObject borrowed} instance to be disposed.
      *
-     * @throws Exception if the pool cannot be cleared
+     * @throws Exception if the instance cannot be invalidated
      */
-    void clear() throws Exception, UnsupportedOperationException;
+    void invalidateObject(T obj) throws Exception;
 
     /**
-     * Closes this pool, and free any resources associated with it.
-     * <p>
-     * Calling {@link #addObject} or {@link #borrowObject} after invoking this
-     * method on a pool will cause them to throw an {@link IllegalStateException}.
-     * </p>
-     * <p>
-     * Implementations should silently fail if not all resources can be freed.
-     * </p>
+     * Returns an instance to the pool. By contract, <code>obj</code>
+     * <strong>must</strong> have been obtained using {@link #borrowObject()} or
+     * a related method as defined in an implementation or sub-interface.
+     *
+     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     *
+     * @throws IllegalStateException
+     *              if an attempt is made to return an object to the pool that
+     *              is in any state other than allocated (i.e. borrowed).
+     *              Attempting to return an object more than once or attempting
+     *              to return an object that was never borrowed from the pool
+     *              will trigger this exception.
+     *
+     * @throws Exception if an instance cannot be returned to the pool
      */
-    @Override
-    void close();
+    void returnObject(T obj) throws Exception;
 }
diff --git a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
index 2494351..7df2f9a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
@@ -17,15 +17,12 @@
 package org.apache.tomcat.dbcp.pool2;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
 
 /**
@@ -36,11 +33,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
  */
 public final class PoolUtils {
 
-    private static final String MSG_FACTOR_NEGATIVE = "factor must be positive.";
     private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
-    private static final String MSG_NULL_KEY = "key must not be null.";
+    public static final String MSG_NULL_KEY = "key must not be null.";
     private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
-    private static final String MSG_NULL_KEYS = "keys must not be null.";
+    public static final String MSG_NULL_KEYS = "keys must not be null.";
     private static final String MSG_NULL_POOL = "pool must not be null.";
 
     /**
@@ -220,15 +216,15 @@ public final class PoolUtils {
      *             when {@link ObjectPool#addObject()} fails.
      * @throws IllegalArgumentException
      *             when <code>pool</code> is <code>null</code>.
+     * @deprecated Use {@link ObjectPool#addObjects(int)}.
      */
+    @Deprecated
     public static <T> void prefill(final ObjectPool<T> pool, final int count)
             throws Exception, IllegalArgumentException {
         if (pool == null) {
             throw new IllegalArgumentException(MSG_NULL_POOL);
         }
-        for (int i = 0; i < count; i++) {
-            pool.addObject();
-        }
+        pool.addObjects(count);
     }
 
     /**
@@ -248,19 +244,16 @@ public final class PoolUtils {
      * @throws IllegalArgumentException
      *             when <code>keyedPool</code> or <code>key</code> is
      *             <code>null</code>.
+     * @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}.
      */
+    @Deprecated
     public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
             final K key, final int count) throws Exception,
             IllegalArgumentException {
         if (keyedPool == null) {
             throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
         }
-        if (key == null) {
-            throw new IllegalArgumentException(MSG_NULL_KEY);
-        }
-        for (int i = 0; i < count; i++) {
-            keyedPool.addObject(key);
-        }
+        keyedPool.addObjects(key, count);
     }
 
     /**
@@ -283,85 +276,16 @@ public final class PoolUtils {
      *             when <code>keyedPool</code>, <code>keys</code>, or any value
      *             in <code>keys</code> is <code>null</code>.
      * @see #prefill(KeyedObjectPool, Object, int)
+     * @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}.
      */
+    @Deprecated
     public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
             final Collection<K> keys, final int count) throws Exception,
             IllegalArgumentException {
         if (keys == null) {
             throw new IllegalArgumentException(MSG_NULL_KEYS);
         }
-        final Iterator<K> iter = keys.iterator();
-        while (iter.hasNext()) {
-            prefill(keyedPool, iter.next(), count);
-        }
-    }
-
-    /**
-     * Returns a synchronized (thread-safe) ObjectPool backed by the specified
-     * ObjectPool.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
-     * </p>
-     *
-     * @param pool
-     *            the ObjectPool to be "wrapped" in a synchronized ObjectPool.
-     * @param <T> the type of objects in the pool
-     * @return a synchronized view of the specified ObjectPool.
-     */
-    public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
-        if (pool == null) {
-            throw new IllegalArgumentException(MSG_NULL_POOL);
-        }
-        /*
-         * assert !(pool instanceof GenericObjectPool) :
-         * "GenericObjectPool is already thread-safe"; assert !(pool instanceof
-         * SoftReferenceObjectPool) :
-         * "SoftReferenceObjectPool is already thread-safe"; assert !(pool
-         * instanceof StackObjectPool) :
-         * "StackObjectPool is already thread-safe"; assert
-         * !"org.apache.commons.pool.composite.CompositeObjectPool"
-         * .equals(pool.getClass().getName()) :
-         * "CompositeObjectPools are already thread-safe";
-         */
-        return new SynchronizedObjectPool<>(pool);
-    }
-
-    /**
-     * Returns a synchronized (thread-safe) KeyedObjectPool backed by the
-     * specified KeyedObjectPool.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
-     * </p>
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be "wrapped" in a synchronized
-     *            KeyedObjectPool.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a synchronized view of the specified KeyedObjectPool.
-     */
-    public static <K, V> KeyedObjectPool<K, V> synchronizedPool(
-            final KeyedObjectPool<K, V> keyedPool) {
-        /*
-         * assert !(keyedPool instanceof GenericKeyedObjectPool) :
-         * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool
-         * instanceof StackKeyedObjectPool) :
-         * "StackKeyedObjectPool is already thread-safe"; assert
-         * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool"
-         * .equals(keyedPool.getClass().getName()) :
-         * "CompositeKeyedObjectPools are already thread-safe";
-         */
-        return new SynchronizedKeyedObjectPool<>(keyedPool);
+        keyedPool.addObjects(keys, count);
     }
 
     /**
@@ -396,167 +320,6 @@ public final class PoolUtils {
     }
 
     /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     *
-     * @param pool
-     *            the ObjectPool to be decorated so it shrinks its idle count
-     *            when possible.
-     * @param <T> the type of objects in the pool
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(ObjectPool, float)
-     */
-    public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
-        return erodingPool(pool, 1f);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     * <p>
-     * The factor parameter provides a mechanism to tweak the rate at which the
-     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
-     * try to shrink its size more often. Values greater than 1 cause the pool
-     * to less frequently try to shrink its size.
-     * </p>
-     *
-     * @param pool
-     *            the ObjectPool to be decorated so it shrinks its idle count
-     *            when possible.
-     * @param factor
-     *            a positive value to scale the rate at which the pool tries to
-     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
-     *            shrinks more aggressively. If 1 &lt; factor then the pool
-     *            shrinks less aggressively.
-     * @param <T> the type of objects in the pool
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(ObjectPool)
-     */
-    public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool,
-            final float factor) {
-        if (pool == null) {
-            throw new IllegalArgumentException(MSG_NULL_POOL);
-        }
-        if (factor <= 0f) {
-            throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
-        }
-        return new ErodingObjectPool<>(pool, factor);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be decorated so it shrinks its idle
-     *            count when possible.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(KeyedObjectPool, float)
-     * @see #erodingPool(KeyedObjectPool, float, boolean)
-     */
-    public static <K, V> KeyedObjectPool<K, V> erodingPool(
-            final KeyedObjectPool<K, V> keyedPool) {
-        return erodingPool(keyedPool, 1f);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     * <p>
-     * The factor parameter provides a mechanism to tweak the rate at which the
-     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
-     * try to shrink its size more often. Values greater than 1 cause the pool
-     * to less frequently try to shrink its size.
-     * </p>
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be decorated so it shrinks its idle
-     *            count when possible.
-     * @param factor
-     *            a positive value to scale the rate at which the pool tries to
-     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
-     *            shrinks more aggressively. If 1 &lt; factor then the pool
-     *            shrinks less aggressively.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(KeyedObjectPool, float, boolean)
-     */
-    public static <K, V> KeyedObjectPool<K, V> erodingPool(
-            final KeyedObjectPool<K, V> keyedPool, final float factor) {
-        return erodingPool(keyedPool, factor, false);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     * <p>
-     * The factor parameter provides a mechanism to tweak the rate at which the
-     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
-     * try to shrink its size more often. Values greater than 1 cause the pool
-     * to less frequently try to shrink its size.
-     * </p>
-     * <p>
-     * The perKey parameter determines if the pool shrinks on a whole pool basis
-     * or a per key basis. When perKey is false, the keys do not have an effect
-     * on the rate at which the pool tries to shrink its size. When perKey is
-     * true, each key is shrunk independently.
-     * </p>
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be decorated so it shrinks its idle
-     *            count when possible.
-     * @param factor
-     *            a positive value to scale the rate at which the pool tries to
-     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
-     *            shrinks more aggressively. If 1 &lt; factor then the pool
-     *            shrinks less aggressively.
-     * @param perKey
-     *            when true, each key is treated independently.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(KeyedObjectPool)
-     * @see #erodingPool(KeyedObjectPool, float)
-     */
-    public static <K, V> KeyedObjectPool<K, V> erodingPool(
-            final KeyedObjectPool<K, V> keyedPool, final float factor,
-            final boolean perKey) {
-        if (keyedPool == null) {
-            throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
-        }
-        if (factor <= 0f) {
-            throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
-        }
-        if (perKey) {
-            return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor);
-        }
-        return new ErodingKeyedObjectPool<>(keyedPool, factor);
-    }
-
-    /**
      * Gets the <code>Timer</code> for checking keyedPool's idle count.
      *
      * @return the {@link Timer} for checking keyedPool's idle count.
@@ -718,73 +481,51 @@ public final class PoolUtils {
     }
 
     /**
-     * A synchronized (thread-safe) ObjectPool backed by the specified
-     * ObjectPool.
+     * A fully synchronized PooledObjectFactory that wraps a
+     * PooledObjectFactory and synchronizes access to the wrapped factory
+     * methods.
      * <p>
      * <b>Note:</b> This should not be used on pool implementations that already
      * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
+     * Pool library.
      * </p>
      *
-     * @param <T> type of objects in the pool
+     * @param <T> pooled object factory type
      */
-    private static final class SynchronizedObjectPool<T> implements ObjectPool<T> {
+    private static final class SynchronizedPooledObjectFactory<T> implements
+            PooledObjectFactory<T> {
 
-        /**
-         * Object whose monitor is used to synchronize methods on the wrapped
-         * pool.
-         */
-        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+        /** Synchronization lock */
+        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
 
-        /** the underlying object pool */
-        private final ObjectPool<T> pool;
+        /** Wrapped factory */
+        private final PooledObjectFactory<T> factory;
 
         /**
-         * Creates a new SynchronizedObjectPool wrapping the given pool.
+         * Creates a SynchronizedPoolableObjectFactory wrapping the given
+         * factory.
          *
-         * @param pool
-         *            the ObjectPool to be "wrapped" in a synchronized
-         *            ObjectPool.
+         * @param factory
+         *            underlying factory to wrap
          * @throws IllegalArgumentException
-         *             if the pool is null
+         *             if the factory is null
          */
-        SynchronizedObjectPool(final ObjectPool<T> pool)
+        SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
                 throws IllegalArgumentException {
-            if (pool == null) {
-                throw new IllegalArgumentException(MSG_NULL_POOL);
-            }
-            this.pool = pool;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public T borrowObject() throws Exception, NoSuchElementException,
-                IllegalStateException {
-            final WriteLock writeLock = readWriteLock.writeLock();
-            writeLock.lock();
-            try {
-                return pool.borrowObject();
-            } finally {
-                writeLock.unlock();
+            if (factory == null) {
+                throw new IllegalArgumentException("factory must not be null.");
             }
+            this.factory = factory;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public void returnObject(final T obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public PooledObject<T> makeObject() throws Exception {
             writeLock.lock();
             try {
-                pool.returnObject(obj);
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                return factory.makeObject();
             } finally {
                 writeLock.unlock();
             }
@@ -794,13 +535,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void invalidateObject(final T obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void destroyObject(final PooledObject<T> p) throws Exception {
             writeLock.lock();
             try {
-                pool.invalidateObject(obj);
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                factory.destroyObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -810,12 +548,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void addObject() throws Exception, IllegalStateException,
-                UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public boolean validateObject(final PooledObject<T> p) {
             writeLock.lock();
             try {
-                pool.addObject();
+                return factory.validateObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -825,39 +561,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public int getNumIdle() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return pool.getNumIdle();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return pool.getNumActive();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void activateObject(final PooledObject<T> p) throws Exception {
             writeLock.lock();
             try {
-                pool.clear();
+                factory.activateObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -867,13 +574,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void close() {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void passivateObject(final PooledObject<T> p) throws Exception {
             writeLock.lock();
             try {
-                pool.close();
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                factory.passivateObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -885,83 +589,62 @@ public final class PoolUtils {
         @Override
         public String toString() {
             final StringBuilder sb = new StringBuilder();
-            sb.append("SynchronizedObjectPool");
-            sb.append("{pool=").append(pool);
+            sb.append("SynchronizedPoolableObjectFactory");
+            sb.append("{factory=").append(factory);
             sb.append('}');
             return sb.toString();
         }
     }
 
     /**
-     * A synchronized (thread-safe) KeyedObjectPool backed by the specified
-     * KeyedObjectPool.
+     * A fully synchronized KeyedPooledObjectFactory that wraps a
+     * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
+     * methods.
      * <p>
      * <b>Note:</b> This should not be used on pool implementations that already
      * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
+     * Pool library.
      * </p>
      *
-     * @param <K> object pool key type
-     * @param <V> object pool value type
+     * @param <K> pooled object factory key type
+     * @param <V> pooled object factory key value
      */
-    private static final class SynchronizedKeyedObjectPool<K, V> implements
-            KeyedObjectPool<K, V> {
+    private static final class SynchronizedKeyedPooledObjectFactory<K, V>
+            implements KeyedPooledObjectFactory<K, V> {
 
-        /**
-         * Object whose monitor is used to synchronize methods on the wrapped
-         * pool.
-         */
-        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+        /** Synchronization lock */
+        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
 
-        /** Underlying object pool */
-        private final KeyedObjectPool<K, V> keyedPool;
+        /** Wrapped factory */
+        private final KeyedPooledObjectFactory<K, V> keyedFactory;
 
         /**
-         * Creates a new SynchronizedKeyedObjectPool wrapping the given pool
+         * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
+         * factory.
          *
-         * @param keyedPool
-         *            KeyedObjectPool to wrap
+         * @param keyedFactory
+         *            underlying factory to wrap
          * @throws IllegalArgumentException
-         *             if keyedPool is null
+         *             if the factory is null
          */
-        SynchronizedKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool)
+        SynchronizedKeyedPooledObjectFactory(
+                final KeyedPooledObjectFactory<K, V> keyedFactory)
                 throws IllegalArgumentException {
-            if (keyedPool == null) {
+            if (keyedFactory == null) {
                 throw new IllegalArgumentException(
-                        MSG_NULL_KEYED_POOL);
-            }
-            this.keyedPool = keyedPool;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public V borrowObject(final K key) throws Exception,
-                NoSuchElementException, IllegalStateException {
-            final WriteLock writeLock = readWriteLock.writeLock();
-            writeLock.lock();
-            try {
-                return keyedPool.borrowObject(key);
-            } finally {
-                writeLock.unlock();
+                        "keyedFactory must not be null.");
             }
+            this.keyedFactory = keyedFactory;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public void returnObject(final K key, final V obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public PooledObject<V> makeObject(final K key) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.returnObject(key, obj);
-            } catch (final Exception e) {
-                // swallowed
+                return keyedFactory.makeObject(key);
             } finally {
                 writeLock.unlock();
             }
@@ -971,13 +654,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void invalidateObject(final K key, final V obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.invalidateObject(key, obj);
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                keyedFactory.destroyObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -987,12 +667,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void addObject(final K key) throws Exception,
-                IllegalStateException, UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public boolean validateObject(final K key, final PooledObject<V> p) {
             writeLock.lock();
             try {
-                keyedPool.addObject(key);
+                return keyedFactory.validateObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -1002,67 +680,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public int getNumIdle(final K key) {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumIdle(key);
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive(final K key) {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumActive(key);
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumIdle();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumActive();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void activateObject(final K key, final PooledObject<V> p) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.clear();
+                keyedFactory.activateObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -1072,263 +693,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void clear(final K key) throws Exception,
-                UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.clear(key);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void close() {
-            final WriteLock writeLock = readWriteLock.writeLock();
-            writeLock.lock();
-            try {
-                keyedPool.close();
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("SynchronizedKeyedObjectPool");
-            sb.append("{keyedPool=").append(keyedPool);
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-    /**
-     * A fully synchronized PooledObjectFactory that wraps a
-     * PooledObjectFactory and synchronizes access to the wrapped factory
-     * methods.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library.
-     * </p>
-     *
-     * @param <T> pooled object factory type
-     */
-    private static final class SynchronizedPooledObjectFactory<T> implements
-            PooledObjectFactory<T> {
-
-        /** Synchronization lock */
-        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
-
-        /** Wrapped factory */
-        private final PooledObjectFactory<T> factory;
-
-        /**
-         * Creates a SynchronizedPoolableObjectFactory wrapping the given
-         * factory.
-         *
-         * @param factory
-         *            underlying factory to wrap
-         * @throws IllegalArgumentException
-         *             if the factory is null
-         */
-        SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
-                throws IllegalArgumentException {
-            if (factory == null) {
-                throw new IllegalArgumentException("factory must not be null.");
-            }
-            this.factory = factory;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public PooledObject<T> makeObject() throws Exception {
-            writeLock.lock();
-            try {
-                return factory.makeObject();
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void destroyObject(final PooledObject<T> p) throws Exception {
-            writeLock.lock();
-            try {
-                factory.destroyObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean validateObject(final PooledObject<T> p) {
-            writeLock.lock();
-            try {
-                return factory.validateObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void activateObject(final PooledObject<T> p) throws Exception {
-            writeLock.lock();
-            try {
-                factory.activateObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void passivateObject(final PooledObject<T> p) throws Exception {
-            writeLock.lock();
-            try {
-                factory.passivateObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("SynchronizedPoolableObjectFactory");
-            sb.append("{factory=").append(factory);
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-    /**
-     * A fully synchronized KeyedPooledObjectFactory that wraps a
-     * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
-     * methods.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library.
-     * </p>
-     *
-     * @param <K> pooled object factory key type
-     * @param <V> pooled object factory key value
-     */
-    private static final class SynchronizedKeyedPooledObjectFactory<K, V>
-            implements KeyedPooledObjectFactory<K, V> {
-
-        /** Synchronization lock */
-        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
-
-        /** Wrapped factory */
-        private final KeyedPooledObjectFactory<K, V> keyedFactory;
-
-        /**
-         * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
-         * factory.
-         *
-         * @param keyedFactory
-         *            underlying factory to wrap
-         * @throws IllegalArgumentException
-         *             if the factory is null
-         */
-        SynchronizedKeyedPooledObjectFactory(
-                final KeyedPooledObjectFactory<K, V> keyedFactory)
-                throws IllegalArgumentException {
-            if (keyedFactory == null) {
-                throw new IllegalArgumentException(
-                        "keyedFactory must not be null.");
-            }
-            this.keyedFactory = keyedFactory;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public PooledObject<V> makeObject(final K key) throws Exception {
-            writeLock.lock();
-            try {
-                return keyedFactory.makeObject(key);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
-            writeLock.lock();
-            try {
-                keyedFactory.destroyObject(key, p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean validateObject(final K key, final PooledObject<V> p) {
-            writeLock.lock();
-            try {
-                return keyedFactory.validateObject(key, p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void activateObject(final K key, final PooledObject<V> p) throws Exception {
-            writeLock.lock();
-            try {
-                keyedFactory.activateObject(key, p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
-            writeLock.lock();
-            try {
-                keyedFactory.passivateObject(key, p);
+                keyedFactory.passivateObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -1346,492 +714,4 @@ public final class PoolUtils {
             return sb.toString();
         }
     }
-
-    /**
-     * Encapsulate the logic for when the next poolable object should be
-     * discarded. Each time update is called, the next time to shrink is
-     * recomputed, based on the float factor, number of idle instances in the
-     * pool and high water mark. Float factor is assumed to be between 0 and 1.
-     * Values closer to 1 cause less frequent erosion events. Erosion event
-     * timing also depends on numIdle. When this value is relatively high (close
-     * to previously established high water mark), erosion occurs more
-     * frequently.
-     */
-    private static final class ErodingFactor {
-        /** Determines frequency of "erosion" events */
-        private final float factor;
-
-        /** Time of next shrink event */
-        private transient volatile long nextShrink;
-
-        /** High water mark - largest numIdle encountered */
-        private transient volatile int idleHighWaterMark;
-
-        /**
-         * Creates a new ErodingFactor with the given erosion factor.
-         *
-         * @param factor
-         *            erosion factor
-         */
-        public ErodingFactor(final float factor) {
-            this.factor = factor;
-            nextShrink = System.currentTimeMillis() + (long) (900000 * factor); // now
-                                                                                // +
-                                                                                // 15
-                                                                                // min
-                                                                                // *
-                                                                                // factor
-            idleHighWaterMark = 1;
-        }
-
-        /**
-         * Updates internal state using the supplied time and numIdle.
-         *
-         * @param now
-         *            current time
-         * @param numIdle
-         *            number of idle elements in the pool
-         */
-        public void update(final long now, final int numIdle) {
-            final int idle = Math.max(0, numIdle);
-            idleHighWaterMark = Math.max(idle, idleHighWaterMark);
-            final float maxInterval = 15f;
-            final float minutes = maxInterval +
-                    ((1f - maxInterval) / idleHighWaterMark) * idle;
-            nextShrink = now + (long) (minutes * 60000f * factor);
-        }
-
-        /**
-         * Returns the time of the next erosion event.
-         *
-         * @return next shrink time
-         */
-        public long getNextShrink() {
-            return nextShrink;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingFactor{" + "factor=" + factor +
-                    ", idleHighWaterMark=" + idleHighWaterMark + '}';
-        }
-    }
-
-    /**
-     * Decorates an object pool, adding "eroding" behavior. Based on the
-     * configured {@link #factor erosion factor}, objects returning to the pool
-     * may be invalidated instead of being added to idle capacity.
-     *
-     * @param <T> type of objects in the pool
-     */
-    private static class ErodingObjectPool<T> implements ObjectPool<T> {
-
-        /** Underlying object pool */
-        private final ObjectPool<T> pool;
-
-        /** Erosion factor */
-        private final ErodingFactor factor;
-
-        /**
-         * Creates an ErodingObjectPool wrapping the given pool using the
-         * specified erosion factor.
-         *
-         * @param pool
-         *            underlying pool
-         * @param factor
-         *            erosion factor - determines the frequency of erosion
-         *            events
-         * @see #factor
-         */
-        public ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
-            this.pool = pool;
-            this.factor = new ErodingFactor(factor);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public T borrowObject() throws Exception, NoSuchElementException,
-                IllegalStateException {
-            return pool.borrowObject();
-        }
-
-        /**
-         * Returns obj to the pool, unless erosion is triggered, in which case
-         * obj is invalidated. Erosion is triggered when there are idle
-         * instances in the pool and more than the {@link #factor erosion
-         * factor}-determined time has elapsed since the last returnObject
-         * activation.
-         *
-         * @param obj
-         *            object to return or invalidate
-         * @see #factor
-         */
-        @Override
-        public void returnObject(final T obj) {
-            boolean discard = false;
-            final long now = System.currentTimeMillis();
-            synchronized (pool) {
-                if (factor.getNextShrink() < now) { // XXX: Pool 3: move test
-                                                    // out of sync block
-                    final int numIdle = pool.getNumIdle();
-                    if (numIdle > 0) {
-                        discard = true;
-                    }
-
-                    factor.update(now, numIdle);
-                }
-            }
-            try {
-                if (discard) {
-                    pool.invalidateObject(obj);
-                } else {
-                    pool.returnObject(obj);
-                }
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void invalidateObject(final T obj) {
-            try {
-                pool.invalidateObject(obj);
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void addObject() throws Exception, IllegalStateException,
-                UnsupportedOperationException {
-            pool.addObject();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle() {
-            return pool.getNumIdle();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            return pool.getNumActive();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            pool.clear();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void close() {
-            try {
-                pool.close();
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingObjectPool{" + "factor=" + factor + ", pool=" +
-                    pool + '}';
-        }
-    }
-
-    /**
-     * Decorates a keyed object pool, adding "eroding" behavior. Based on the
-     * configured erosion factor, objects returning to the pool
-     * may be invalidated instead of being added to idle capacity.
-     *
-     * @param <K> object pool key type
-     * @param <V> object pool value type
-     */
-    private static class ErodingKeyedObjectPool<K, V> implements
-            KeyedObjectPool<K, V> {
-
-        /** Underlying pool */
-        private final KeyedObjectPool<K, V> keyedPool;
-
-        /** Erosion factor */
-        private final ErodingFactor erodingFactor;
-
-        /**
-         * Creates an ErodingObjectPool wrapping the given pool using the
-         * specified erosion factor.
-         *
-         * @param keyedPool
-         *            underlying pool
-         * @param factor
-         *            erosion factor - determines the frequency of erosion
-         *            events
-         * @see #erodingFactor
-         */
-        public ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
-                final float factor) {
-            this(keyedPool, new ErodingFactor(factor));
-        }
-
-        /**
-         * Creates an ErodingObjectPool wrapping the given pool using the
-         * specified erosion factor.
-         *
-         * @param keyedPool
-         *            underlying pool - must not be null
-         * @param erodingFactor
-         *            erosion factor - determines the frequency of erosion
-         *            events
-         * @see #erodingFactor
-         */
-        protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
-                final ErodingFactor erodingFactor) {
-            if (keyedPool == null) {
-                throw new IllegalArgumentException(
-                        MSG_NULL_KEYED_POOL);
-            }
-            this.keyedPool = keyedPool;
-            this.erodingFactor = erodingFactor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public V borrowObject(final K key) throws Exception,
-                NoSuchElementException, IllegalStateException {
-            return keyedPool.borrowObject(key);
-        }
-
-        /**
-         * Returns obj to the pool, unless erosion is triggered, in which case
-         * obj is invalidated. Erosion is triggered when there are idle
-         * instances in the pool associated with the given key and more than the
-         * configured {@link #erodingFactor erosion factor} time has elapsed
-         * since the last returnObject activation.
-         *
-         * @param obj
-         *            object to return or invalidate
-         * @param key
-         *            key
-         * @see #erodingFactor
-         */
-        @Override
-        public void returnObject(final K key, final V obj) throws Exception {
-            boolean discard = false;
-            final long now = System.currentTimeMillis();
-            final ErodingFactor factor = getErodingFactor(key);
-            synchronized (keyedPool) {
-                if (factor.getNextShrink() < now) {
-                    final int numIdle = getNumIdle(key);
-                    if (numIdle > 0) {
-                        discard = true;
-                    }
-
-                    factor.update(now, numIdle);
-                }
-            }
-            try {
-                if (discard) {
-                    keyedPool.invalidateObject(key, obj);
-                } else {
-                    keyedPool.returnObject(key, obj);
-                }
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * Returns the eroding factor for the given key
-         *
-         * @param key
-         *            key
-         * @return eroding factor for the given keyed pool
-         */
-        protected ErodingFactor getErodingFactor(final K key) {
-            return erodingFactor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void invalidateObject(final K key, final V obj) {
-            try {
-                keyedPool.invalidateObject(key, obj);
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void addObject(final K key) throws Exception,
-                IllegalStateException, UnsupportedOperationException {
-            keyedPool.addObject(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle() {
-            return keyedPool.getNumIdle();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle(final K key) {
-            return keyedPool.getNumIdle(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            return keyedPool.getNumActive();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive(final K key) {
-            return keyedPool.getNumActive(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            keyedPool.clear();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear(final K key) throws Exception,
-                UnsupportedOperationException {
-            keyedPool.clear(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void close() {
-            try {
-                keyedPool.close();
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * Returns the underlying pool
-         *
-         * @return the keyed pool that this ErodingKeyedObjectPool wraps
-         */
-        protected KeyedObjectPool<K, V> getKeyedPool() {
-            return keyedPool;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingKeyedObjectPool{" + "factor=" +
-                    erodingFactor + ", keyedPool=" + keyedPool + '}';
-        }
-    }
-
-    /**
-     * Extends ErodingKeyedObjectPool to allow erosion to take place on a
-     * per-key basis. Timing of erosion events is tracked separately for
-     * separate keyed pools.
-     *
-     * @param <K> object pool key type
-     * @param <V> object pool value type
-     */
-    private static final class ErodingPerKeyKeyedObjectPool<K, V> extends
-            ErodingKeyedObjectPool<K, V> {
-
-        /** Erosion factor - same for all pools */
-        private final float factor;
-
-        /** Map of ErodingFactor instances keyed on pool keys */
-        private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<K, ErodingFactor>());
-
-        /**
-         * Creates a new ErordingPerKeyKeyedObjectPool decorating the given keyed
-         * pool with the specified erosion factor.
-         *
-         * @param keyedPool
-         *            underlying keyed pool
-         * @param factor
-         *            erosion factor
-         */
-        public ErodingPerKeyKeyedObjectPool(
-                final KeyedObjectPool<K, V> keyedPool, final float factor) {
-            super(keyedPool, null);
-            this.factor = factor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        protected ErodingFactor getErodingFactor(final K key) {
-            ErodingFactor eFactor = factors.get(key);
-            // this may result in two ErodingFactors being created for a key
-            // since they are small and cheap this is okay.
-            if (eFactor == null) {
-                eFactor = new ErodingFactor(this.factor);
-                factors.put(key, eFactor);
-            }
-            return eFactor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +
-                    ", keyedPool=" + getKeyedPool() + '}';
-        }
-    }
 }
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
index 361b3d8..1bfb803 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
@@ -24,6 +24,7 @@ import java.util.Deque;
  * state, for the pooled objects.
  * <p>
  * Implementations of this class are required to be thread-safe.
+ * </p>
  *
  * @param <T> the type of object in the pool
  *
@@ -185,7 +186,7 @@ public interface PooledObject<T> extends Comparable<PooledObject<T>> {
      * @param requireFullStackTrace the new configuration setting for abandoned object logging
      * @since 2.7.0
      */
-    void setRequireFullStackTrace(boolean requireFullStackTrace);
+    void setRequireFullStackTrace(final boolean requireFullStackTrace);
 
     /**
      * Record the current stack trace as the last time the object was used.
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
index fdacc6e..fc618a5 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
@@ -31,7 +31,9 @@ import org.apache.tomcat.dbcp.pool2.PooledObject;
  *     {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} /
  *     {@link GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()}
  * </ul>
+ * <p>
  * This class is immutable and thread-safe.
+ * </p>
  *
  * @param <T> the type of objects in the pool
  *
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
index 49766f0..b124676 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
@@ -22,6 +22,7 @@ package org.apache.tomcat.dbcp.pool2.impl;
  * its own specific configuration attributes.
  * <p>
  * This class is immutable and thread-safe.
+ * </p>
  *
  * @since 2.0
  */
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
index 01dc542..93c7a84 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
@@ -17,6 +17,7 @@
 package org.apache.tomcat.dbcp.pool2.impl;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -50,10 +51,12 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectState;
  * {@link #borrowObject borrowObject} methods. Each time a new key value is
  * provided to one of these methods, a sub-new pool is created under the given
  * key to be managed by the containing <code>GenericKeyedObjectPool.</code>
+ * </p>
  * <p>
  * Note that the current implementation uses a ConcurrentHashMap which uses
  * equals() to compare keys.
  * This means that distinct instance keys must be distinguishable using equals.
+ * </p>
  * <p>
  * Optionally, one may configure the pool to examine and possibly evict objects
  * as they sit idle in the pool and to ensure that a minimum number of idle
@@ -62,12 +65,15 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectState;
  * configuring this optional feature. Eviction runs contend with client threads
  * for access to objects in the pool, so if they run too frequently performance
  * issues may result.
+ * </p>
  * <p>
  * Implementation note: To prevent possible deadlocks, care has been taken to
  * ensure that no call to a factory method will occur within a synchronization
  * block. See POOL-125 and DBCP-44 for more information.
+ * </p>
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @see GenericObjectPool
  *
@@ -447,6 +453,11 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
 
         final ObjectDeque<T> objectDeque = poolMap.get(key);
 
+        if (objectDeque == null) {
+            throw new IllegalStateException(
+                    "No keyed pool found under the given key.");
+        }
+
         final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj));
 
         if (p == null) {
@@ -1077,8 +1088,16 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
         final ObjectDeque<T> objectDeque = register(key);
 
         try {
-            final boolean isIdle = objectDeque.getIdleObjects().remove(toDestroy);
-
+            boolean isIdle;
+            synchronized(toDestroy) {
+                // Check idle state directly
+                isIdle = toDestroy.getState().equals(PooledObjectState.IDLE);
+                // If idle, not under eviction test, or always is true, remove instance,
+                // updating isIdle if instance is found in idle objects
+                if (isIdle || always) {
+                    isIdle = objectDeque.getIdleObjects().remove(toDestroy);
+                }
+            }
             if (isIdle || always) {
                 objectDeque.getAllObjects().remove(new IdentityWrapper<>(toDestroy.getObject()));
                 toDestroy.invalidate();
@@ -1151,10 +1170,9 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
      */
     private void deregister(final K k) {
         Lock lock = keyLock.readLock();
-        ObjectDeque<T> objectDeque;
         try {
             lock.lock();
-            objectDeque = poolMap.get(k);
+            final ObjectDeque<T> objectDeque = poolMap.get(k);
             final long numInterested = objectDeque.getNumInterested().decrementAndGet();
             if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) {
                 // Potential to remove key
@@ -1244,6 +1262,58 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
     }
 
     /**
+     * Calls {@link KeyedObjectPool#addObject(Object)} with each
+     * key in <code>keys</code> for <code>count</code> number of times. This has
+     * the same effect as calling {@link #addObjects(Object, int)}
+     * for each key in the <code>keys</code> collection.
+     *
+     * @param keys
+     *            {@link Collection} of keys to add objects for.
+     * @param count
+     *            the number of idle objects to add for each <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>keyedPool</code>, <code>keys</code>, or any value
+     *             in <code>keys</code> is <code>null</code>.
+     * @see #addObjects(Object, int)
+     */
+    @Override
+    public void addObjects(final Collection<K> keys, final int count) throws Exception, IllegalArgumentException {
+        if (keys == null) {
+            throw new IllegalArgumentException(PoolUtils.MSG_NULL_KEYS);
+        }
+        final Iterator<K> iter = keys.iterator();
+        while (iter.hasNext()) {
+            addObjects(iter.next(), count);
+        }
+    }
+
+    /**
+     * Calls {@link KeyedObjectPool#addObject(Object)}
+     * <code>key</code> <code>count</code> number of times.
+     *
+     * @param key
+     *            the key to add objects for.
+     * @param count
+     *            the number of idle objects to add for <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>key</code> is <code>null</code>.
+     * @since 2.8.0
+     */
+    @Override
+    public void addObjects(final K key, final int count) throws Exception, IllegalArgumentException {
+        if (key == null) {
+            throw new IllegalArgumentException(PoolUtils.MSG_NULL_KEY);
+        }
+        for (int i = 0; i < count; i++) {
+            addObject(key);
+        }
+    }
+
+    /**
      * Add an object to the set of idle objects for a given key.
      *
      * @param key The key to associate with the idle object
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
index c72b701..4a9909d 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
@@ -38,7 +38,8 @@ import org.apache.tomcat.dbcp.pool2.UsageTracking;
  * <p>
  * When coupled with the appropriate {@link PooledObjectFactory},
  * <code>GenericObjectPool</code> provides robust pooling functionality for
- * arbitrary objects.</p>
+ * arbitrary objects.
+ * </p>
  * <p>
  * Optionally, one may configure the pool to examine and possibly evict objects
  * as they sit idle in the pool and to ensure that a minimum number of idle
@@ -46,7 +47,8 @@ import org.apache.tomcat.dbcp.pool2.UsageTracking;
  * which runs asynchronously. Caution should be used when configuring this
  * optional feature. Eviction runs contend with client threads for access to
  * objects in the pool, so if they run too frequently performance issues may
- * result.</p>
+ * result.
+ * </p>
  * <p>
  * The pool can also be configured to detect and remove "abandoned" objects,
  * i.e. objects that have been checked out of the pool but neither used nor
@@ -59,13 +61,16 @@ import org.apache.tomcat.dbcp.pool2.UsageTracking;
  * their last use will be queried
  * using the <code>getLastUsed</code> method on that interface; otherwise
  * abandonment is determined by how long an object has been checked out from
- * the pool.</p>
+ * the pool.
+ * </p>
  * <p>
  * Implementation note: To prevent possible deadlocks, care has been taken to
  * ensure that no call to a factory method will occur within a synchronization
- * block. See POOL-125 and DBCP-44 for more information.</p>
+ * block. See POOL-125 and DBCP-44 for more information.
+ * </p>
  * <p>
- * This class is intended to be thread-safe.</p>
+ * This class is intended to be thread-safe.
+ * </p>
  *
  * @see GenericKeyedObjectPool
  *
@@ -576,6 +581,11 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
             } catch (final Exception e) {
                 swallowException(e);
             }
+            try {
+                ensureIdle(1, false);
+            } catch (final Exception e) {
+                swallowException(e);
+            }
         } else {
             if (getLifo()) {
                 idleObjects.addFirst(p);
@@ -931,15 +941,6 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
             destroyedCount.incrementAndGet();
             createCount.decrementAndGet();
         }
-
-        if (idleObjects.isEmpty() && idleObjects.hasTakeWaiters()) {
-            // POOL-356.
-            // In case there are already threads waiting on something in the pool
-            // (e.g. idleObjects.takeFirst(); then we need to provide them a fresh instance.
-            // Otherwise they will be stuck forever (or until timeout)
-            final PooledObject<T> freshPooled = create();
-            idleObjects.put(freshPooled);
-        }
     }
 
     @Override
@@ -1005,6 +1006,23 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
     }
 
     /**
+     * Calls {@link ObjectPool#addObject()} <code>count</code>
+     * number of times.
+     *
+     * @param count
+     *            the number of idle objects to add.
+     * @throws Exception
+     *             when {@link ObjectPool#addObject()} fails.
+     * @since 2.8.0
+     */
+    @Override
+    public void addObjects(final int count) throws Exception {
+        for (int i = 0; i < count; i++) {
+            addObject();
+        }
+    }
+
+    /**
      * Adds the provided wrapped pooled object to the set of idle objects for
      * this pool. The object must already be part of the pool.  If {@code p}
      * is null, this is a no-op (no exception, but no impact on the pool).
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java b/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
index 5a51b92..b539aed 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
@@ -26,6 +26,7 @@ import java.util.concurrent.locks.ReentrantLock;
  * class is intended for internal use only.
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @since 2.0
  */
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java b/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
index be92f91..75e925e 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
@@ -34,6 +34,7 @@ import java.util.concurrent.locks.Condition;
  * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
  * dynamically created upon each insertion unless this would bring the
  * deque above capacity.
+ * </p>
  *
  * <p>Most operations run in constant time (ignoring time spent
  * blocking).  Exceptions include {@link #remove(Object) remove},
@@ -41,14 +42,17 @@ import java.util.concurrent.locks.Condition;
  * #removeLastOccurrence removeLastOccurrence}, {@link #contains
  * contains}, {@link #iterator iterator.remove()}, and the bulk
  * operations, all of which run in linear time.
+ * </p>
  *
  * <p>This class and its iterator implement all of the
  * <em>optional</em> methods of the {@link Collection} and {@link
  * Iterator} interfaces.
+ * </p>
  *
  * <p>This class is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
+ * </p>
  *
  * @param <E> the type of elements held in this collection
  *
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
index 61741be..e417b48 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
@@ -32,6 +32,7 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectFactory;
  * {@link org.apache.tomcat.dbcp.pool2.ObjectPool}.
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @param <T>
  *            Type of element pooled in this pool.
@@ -185,6 +186,8 @@ public class SoftReferenceObjectPool<T> extends BaseObjectPool<T> {
      *
      * @param obj
      *            instance to return to the pool
+     * @throws IllegalArgumentException
+     *            if obj is not currently part of this pool
      */
     @Override
     public synchronized void returnObject(final T obj) throws Exception {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 9b8c487..86adeab 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -213,6 +213,10 @@
         Update the internal fork of Apache Commons FileUpload to 2317552
         (2019-12-06, 2.0-SNAPSHOT). Refactoring. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons Pool 2 to 6092f92 (2019-12-06,
+        2.8.0-SNAPSHOT). Clean-up and minor refactoring. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 15/18: Add an atomic method to rotate session ID and return new value. Use it.

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 6dcf03e3784f3d7f0c82e8cd3531cf772ae48a37
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 12:13:15 2019 +0000

    Add an atomic method to rotate session ID and return new value. Use it.
---
 java/org/apache/catalina/Manager.java             | 33 +++++++++++++++++++++++
 java/org/apache/catalina/connector/Request.java   |  3 +--
 java/org/apache/catalina/session/ManagerBase.java |  7 +++++
 3 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/Manager.java b/java/org/apache/catalina/Manager.java
index 4c8275f..0fe745b 100644
--- a/java/org/apache/catalina/Manager.java
+++ b/java/org/apache/catalina/Manager.java
@@ -215,11 +215,44 @@ public interface Manager {
      * session ID.
      *
      * @param session   The session to change the session ID for
+     *
+     * @deprecated Use {@link #rotateSessionId(Session)}.
+     *             Will be removed in Tomcat 10
      */
+    @Deprecated
     public void changeSessionId(Session session);
 
 
     /**
+     * Change the session ID of the current session to a new randomly generated
+     * session ID.
+     *
+     * @param session   The session to change the session ID for
+     *
+     * @return  The new session ID
+     */
+    public default String rotateSessionId(Session session) {
+        String newSessionId = null;
+        // Assume there new Id is a duplicate until we prove it isn't. The
+        // chances of a duplicate are extremely low but the current ManagerBase
+        // code protects against duplicates so this default method does too.
+        boolean duplicate = true;
+        do {
+            newSessionId = getSessionIdGenerator().generateSessionId();
+            try {
+                if (findSession(newSessionId) == null) {
+                    duplicate = false;
+                }
+            } catch (IOException ioe) {
+                // Swallow. An IOE means the ID was known so continue looping
+            }
+        } while (duplicate);
+        changeSessionId(session, newSessionId);
+        return newSessionId;
+    }
+
+
+    /**
      * Change the session ID of the current session to a specified session ID.
      *
      * @param session   The session to change the session ID for
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index bb4039d..954aa3e 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -2697,9 +2697,8 @@ public class Request implements org.apache.catalina.servlet4preview.http.HttpSer
         }
 
         Manager manager = this.getContext().getManager();
-        manager.changeSessionId(session);
 
-        String newSessionId = session.getId();
+        String newSessionId = manager.rotateSessionId(session);
         this.changeSessionId(newSessionId);
 
         return newSessionId;
diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java
index cccda39..894256d 100644
--- a/java/org/apache/catalina/session/ManagerBase.java
+++ b/java/org/apache/catalina/session/ManagerBase.java
@@ -723,8 +723,15 @@ public abstract class ManagerBase extends LifecycleMBeanBase implements Manager
 
     @Override
     public void changeSessionId(Session session) {
+        rotateSessionId(session);
+    }
+
+
+    @Override
+    public String rotateSessionId(Session session) {
         String newId = generateSessionId();
         changeSessionId(session, newId, true, true);
+        return newId;
     }
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 18/18: Refactor wait to make test failure due to timing issues less likely

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 1f9d3e6500fb8543493f20c958dc59cbb3415dfa
Author: god <go...@win-10-x64-dev.homeinbox.net>
AuthorDate: Sat Dec 7 13:27:54 2019 +0000

    Refactor wait to make test failure due to timing issues less likely
---
 test/org/apache/tomcat/util/net/TestSsl.java | 29 +++++++++-------------------
 1 file changed, 9 insertions(+), 20 deletions(-)

diff --git a/test/org/apache/tomcat/util/net/TestSsl.java b/test/org/apache/tomcat/util/net/TestSsl.java
index 8e815f2..b777f2c 100644
--- a/test/org/apache/tomcat/util/net/TestSsl.java
+++ b/test/org/apache/tomcat/util/net/TestSsl.java
@@ -136,28 +136,17 @@ public class TestSsl extends TomcatBaseTest {
 
         socket.startHandshake();
 
-        // One request should be sufficient
-        int requestCount = 0;
-        int listenerComplete = 0;
-        try {
-            while (requestCount < 10) {
-                requestCount++;
-                doRequest(os, r);
-                Assert.assertTrue("Checking no client issuer has been requested",
-                        TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
-                if (listener.isComplete() && listenerComplete == 0) {
-                    listenerComplete = requestCount;
-                }
-            }
-        } catch (AssertionError | IOException e) {
-            String message = "Failed on request number " + requestCount
-                    + " after startHandshake(). " + e.getMessage();
-            log.error(message, e);
-            Assert.fail(message);
+        doRequest(os, r);
+        // Handshake complete appears to be called asynchronously
+        int wait = 0;
+        while (wait < 5000 && !listener.isComplete()) {
+            wait += 50;
+            Thread.sleep(50);
         }
-
+        Assert.assertTrue("Checking no client issuer has been requested",
+                TesterSupport.getLastClientAuthRequestedIssuerCount() == 0);
         Assert.assertTrue(listener.isComplete());
-        System.out.println("Renegotiation completed after " + listenerComplete + " requests");
+        System.out.println("Renegotiation completed after " + wait + " ms");
     }
 
     private void doRequest(OutputStream os, Reader r) throws IOException {


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 01/18: Merge in BCEL changes to ff6941e (2019-12-06, 6.4.2-dev)

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 5d4e832d916bd0e53fca7f2b9036936875bf0427
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 14:18:15 2019 +0000

    Merge in BCEL changes to ff6941e (2019-12-06, 6.4.2-dev)
---
 MERGE.txt                                                  |  2 +-
 java/org/apache/tomcat/util/bcel/Const.java                | 14 ++++++++------
 .../apache/tomcat/util/bcel/classfile/ConstantClass.java   |  2 +-
 .../apache/tomcat/util/bcel/classfile/ConstantDouble.java  |  2 +-
 .../apache/tomcat/util/bcel/classfile/ConstantFloat.java   |  2 +-
 .../apache/tomcat/util/bcel/classfile/ConstantInteger.java |  2 +-
 .../apache/tomcat/util/bcel/classfile/ConstantLong.java    |  2 +-
 webapps/docs/changelog.xml                                 |  4 ++++
 8 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index 18da378..f4fb1f8 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -36,7 +36,7 @@ BCEL
 Sub-tree:
 src/main/java/org/apache/bcel
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
-4b760bb53b57b704006a0a33f7ec187b7e7f5ebc (2019-08-01)
+ff6941e4491c68f6eaf270ff03c1bc1e554c7b42 (2019-12-06)
 
 Codec
 -----
diff --git a/java/org/apache/tomcat/util/bcel/Const.java b/java/org/apache/tomcat/util/bcel/Const.java
index 402b304..bfaeb42 100644
--- a/java/org/apache/tomcat/util/bcel/Const.java
+++ b/java/org/apache/tomcat/util/bcel/Const.java
@@ -23,12 +23,14 @@ package org.apache.tomcat.util.bcel;
 public final class Const {
 
     /** One of the access flags for fields, methods, or classes.
-     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5">
-     *  Flag definitions for Fields in the Java Virtual Machine Specification (Java SE 8 Edition).</a>
-     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6">
-     *  Flag definitions for Methods in the Java Virtual Machine Specification (Java SE 8 Edition).</a>
-     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6-300-D.1-D.1">
-     *  Flag definitions for Classes in the Java Virtual Machine Specification (Java SE 8 Edition).</a>
+     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1">
+     *  Flag definitions for Classes in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
+     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5">
+     *  Flag definitions for Fields in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
+     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6">
+     *  Flag definitions for Methods in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
+     *  @see <a href="http://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.6-300-D.1-D.1">
+     *  Flag definitions for Inner Classes in the Java Virtual Machine Specification (Java SE 9 Edition).</a>
      */
     public static final short ACC_FINAL      = 0x0010;
 
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
index 86e7262..4bce5cc 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
@@ -48,7 +48,7 @@ public final class ConstantClass extends Constant {
     /**
      * @return Name index in constant pool of class name.
      */
-    public final int getNameIndex() {
+    public int getNameIndex() {
         return name_index;
     }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
index 5ba7fcc..1152dbd 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
@@ -48,7 +48,7 @@ public final class ConstantDouble extends Constant {
     /**
      * @return data, i.e., 8 bytes.
      */
-    public final double getBytes() {
+    public double getBytes() {
         return bytes;
     }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
index f372bb9..1fd2450 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
@@ -48,7 +48,7 @@ public final class ConstantFloat extends Constant {
     /**
      * @return data, i.e., 4 bytes.
      */
-    public final float getBytes() {
+    public float getBytes() {
         return bytes;
     }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
index f2c1ba8..0d95983 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
@@ -48,7 +48,7 @@ public final class ConstantInteger extends Constant {
     /**
      * @return data, i.e., 4 bytes.
      */
-    public final int getBytes() {
+    public int getBytes() {
         return bytes;
     }
 }
diff --git a/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java b/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
index d7b245c..d7affef 100644
--- a/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
+++ b/java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
@@ -48,7 +48,7 @@ public final class ConstantLong extends Constant {
     /**
      * @return data, i.e., 8 bytes.
      */
-    public final long getBytes() {
+    public long getBytes() {
         return bytes;
     }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3a287e1..c2fc5de 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -201,6 +201,10 @@
         Expand the coverage of the Chinese translations provided with Apache
         Tomcat. Contributions provided by lins and 磊. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons BCEL to ff6941e (2019-12-06,
+        6.4.2-dev). Code clean-up only. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 17/18: Fix back-port of atomic session ID rotation. Replace default method.

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit d9a1db799cc30d5bce796e3836bbd837531ce79e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 22:10:29 2019 +0000

    Fix back-port of atomic session ID rotation. Replace default method.
---
 java/org/apache/catalina/Manager.java             | 33 -----------------------
 java/org/apache/catalina/connector/Request.java   | 27 ++++++++++++++++++-
 java/org/apache/catalina/session/ManagerBase.java |  1 -
 3 files changed, 26 insertions(+), 35 deletions(-)

diff --git a/java/org/apache/catalina/Manager.java b/java/org/apache/catalina/Manager.java
index 0fe745b..4c8275f 100644
--- a/java/org/apache/catalina/Manager.java
+++ b/java/org/apache/catalina/Manager.java
@@ -215,44 +215,11 @@ public interface Manager {
      * session ID.
      *
      * @param session   The session to change the session ID for
-     *
-     * @deprecated Use {@link #rotateSessionId(Session)}.
-     *             Will be removed in Tomcat 10
      */
-    @Deprecated
     public void changeSessionId(Session session);
 
 
     /**
-     * Change the session ID of the current session to a new randomly generated
-     * session ID.
-     *
-     * @param session   The session to change the session ID for
-     *
-     * @return  The new session ID
-     */
-    public default String rotateSessionId(Session session) {
-        String newSessionId = null;
-        // Assume there new Id is a duplicate until we prove it isn't. The
-        // chances of a duplicate are extremely low but the current ManagerBase
-        // code protects against duplicates so this default method does too.
-        boolean duplicate = true;
-        do {
-            newSessionId = getSessionIdGenerator().generateSessionId();
-            try {
-                if (findSession(newSessionId) == null) {
-                    duplicate = false;
-                }
-            } catch (IOException ioe) {
-                // Swallow. An IOE means the ID was known so continue looping
-            }
-        } while (duplicate);
-        changeSessionId(session, newSessionId);
-        return newSessionId;
-    }
-
-
-    /**
      * Change the session ID of the current session to a specified session ID.
      *
      * @param session   The session to change the session ID for
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 954aa3e..d606c2b 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -83,6 +83,7 @@ import org.apache.catalina.core.AsyncContextImpl;
 import org.apache.catalina.mapper.MappingData;
 import org.apache.catalina.servlet4preview.http.HttpServletMapping;
 import org.apache.catalina.servlet4preview.http.PushBuilder;
+import org.apache.catalina.session.ManagerBase;
 import org.apache.catalina.util.ParameterMap;
 import org.apache.catalina.util.TLSUtil;
 import org.apache.catalina.util.URLEncoder;
@@ -2698,12 +2699,36 @@ public class Request implements org.apache.catalina.servlet4preview.http.HttpSer
 
         Manager manager = this.getContext().getManager();
 
-        String newSessionId = manager.rotateSessionId(session);
+        String newSessionId = rotateSessionId(manager, session);
         this.changeSessionId(newSessionId);
 
         return newSessionId;
     }
 
+    private String rotateSessionId(Manager manager, Session sessiom) {
+        if (manager instanceof ManagerBase) {
+            return ((ManagerBase) manager).rotateSessionId(sessiom);
+        } else {
+            String newSessionId = null;
+            // Assume there new Id is a duplicate until we prove it isn't. The
+            // chances of a duplicate are extremely low but the current ManagerBase
+            // code protects against duplicates so this method does too.
+            boolean duplicate = true;
+            do {
+                newSessionId = manager.getSessionIdGenerator().generateSessionId();
+                try {
+                    if (manager.findSession(newSessionId) == null) {
+                        duplicate = false;
+                    }
+                } catch (IOException ioe) {
+                    // Swallow. An IOE means the ID was known so continue looping
+                }
+            } while (duplicate);
+            manager.changeSessionId(session, newSessionId);
+            return newSessionId;
+        }
+    }
+
     /**
      * @return the session associated with this Request, creating one
      * if necessary and requested.
diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java
index 894256d..74843d0 100644
--- a/java/org/apache/catalina/session/ManagerBase.java
+++ b/java/org/apache/catalina/session/ManagerBase.java
@@ -727,7 +727,6 @@ public abstract class ManagerBase extends LifecycleMBeanBase implements Manager
     }
 
 
-    @Override
     public String rotateSessionId(Session session) {
         String newId = generateSessionId();
         changeSessionId(session, newId, true, true);


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 05/18: Merge in DBCP 2 changes 2 a363390 (2019-12-06, 2.7.1-SNAPSHOT)

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 1706b31a01befb73553d2ae29240ff70c76b3f0c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 16:34:07 2019 +0000

    Merge in DBCP 2 changes 2 a363390 (2019-12-06, 2.7.1-SNAPSHOT)
---
 MERGE.txt                                          |  2 +-
 .../apache/tomcat/dbcp/dbcp2/AbandonedTrace.java   | 92 +++++++++++-----------
 webapps/docs/changelog.xml                         |  4 +
 3 files changed, 51 insertions(+), 47 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index 7daec6d..5551fb2 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -69,4 +69,4 @@ Sub-tree
 src/main/java/org/apache/commons/dbcp2
 src/main/resources/org/apache/commons/dbcp2
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
-4813b7f5456c1f4fecc4f701ac731a71f57db249 (2019-08-09)
+a363906bf7a039f79c07fa3c68b082a69ae035d7 (2019-12-06)
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
index 3969480..671e3e6 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
@@ -58,45 +58,6 @@ public class AbandonedTrace implements TrackedUse {
     }
 
     /**
-     * Initializes abandoned tracing for this object.
-     *
-     * @param parent
-     *            AbandonedTrace parent object.
-     */
-    private void init(final AbandonedTrace parent) {
-        if (parent != null) {
-            parent.addTrace(this);
-        }
-    }
-
-    /**
-     * Gets the last time this object was used in milliseconds.
-     *
-     * @return long time in milliseconds.
-     */
-    @Override
-    public long getLastUsed() {
-        return lastUsedMillis;
-    }
-
-    /**
-     * Sets the time this object was last used to the current time in milliseconds.
-     */
-    protected void setLastUsed() {
-        lastUsedMillis = System.currentTimeMillis();
-    }
-
-    /**
-     * Sets the time in milliseconds this object was last used.
-     *
-     * @param lastUsedMillis
-     *            time in milliseconds.
-     */
-    protected void setLastUsed(final long lastUsedMillis) {
-        this.lastUsedMillis = lastUsedMillis;
-    }
-
-    /**
      * Adds an object to the list of objects being traced.
      *
      * @param trace
@@ -119,6 +80,16 @@ public class AbandonedTrace implements TrackedUse {
     }
 
     /**
+     * Gets the last time this object was used in milliseconds.
+     *
+     * @return long time in milliseconds.
+     */
+    @Override
+    public long getLastUsed() {
+        return lastUsedMillis;
+    }
+
+    /**
      * Gets a list of objects being traced by this object.
      *
      * @return List of objects.
@@ -145,6 +116,30 @@ public class AbandonedTrace implements TrackedUse {
     }
 
     /**
+     * Initializes abandoned tracing for this object.
+     *
+     * @param parent
+     *            AbandonedTrace parent object.
+     */
+    private void init(final AbandonedTrace parent) {
+        if (parent != null) {
+            parent.addTrace(this);
+        }
+    }
+
+    /**
+     * Removes this object the source object is tracing.
+     *
+     * @param source The object tracing
+     * @since 2.7.0
+     */
+    protected void removeThisTrace(final Object source) {
+        if (source instanceof AbandonedTrace) {
+            AbandonedTrace.class.cast(source).removeTrace(this);
+        }
+    }
+
+    /**
      * Removes a child object this object is tracing.
      *
      * @param trace
@@ -167,14 +162,19 @@ public class AbandonedTrace implements TrackedUse {
     }
 
     /**
-     * Removes this object the source object is tracing.
+     * Sets the time this object was last used to the current time in milliseconds.
+     */
+    protected void setLastUsed() {
+        lastUsedMillis = System.currentTimeMillis();
+    }
+
+    /**
+     * Sets the time in milliseconds this object was last used.
      *
-     * @param source The object tracing
-     * @since 2.7.0
+     * @param lastUsedMillis
+     *            time in milliseconds.
      */
-    protected void removeThisTrace(final Object source) {
-        if (source instanceof AbandonedTrace) {
-            AbandonedTrace.class.cast(source).removeTrace(this);
-        }
+    protected void setLastUsed(final long lastUsedMillis) {
+        this.lastUsedMillis = lastUsedMillis;
     }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 86adeab..87e9e84 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -217,6 +217,10 @@
         Update the internal fork of Apache Commons Pool 2 to 6092f92 (2019-12-06,
         2.8.0-SNAPSHOT). Clean-up and minor refactoring. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons DBCP 2 to a36390 (2019-12-06,
+        2.7.1-SNAPSHOT). Minor refactoring. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 09/18: Fix codec

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b8d9fbc7eb1ebbfd27616c8fa477f2c08862e6de
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 19:00:06 2019 +0000

    Fix codec
---
 .../catalina/authenticator/TestBasicAuthParser.java       | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/test/org/apache/catalina/authenticator/TestBasicAuthParser.java b/test/org/apache/catalina/authenticator/TestBasicAuthParser.java
index cc480ff..9f918d2 100644
--- a/test/org/apache/catalina/authenticator/TestBasicAuthParser.java
+++ b/test/org/apache/catalina/authenticator/TestBasicAuthParser.java
@@ -362,26 +362,23 @@ public class TestBasicAuthParser {
     /*
      * invalid base64 string tests
      *
-     * Refer to RFC2045 section 6.8.
+     * Refer to
+     *  - RFC 7617 (Basic Auth)
+     *  - RFC 4648 (base 64)
      */
 
     /*
-     * non-trailing "=" should trigger premature termination of the
-     * decoder, returning a truncated string that will eventually
-     * result in an authentication Assert.failure.
+     * non-trailing "=" is illegal and will be rejected by the parser
      */
-    @Test
+    @Test(expected = IllegalArgumentException.class)
     public void testBadBase64InlineEquals() throws Exception {
         final String BASE64_CRIB = "dXNlcmlkOnNlY3J=dAo=";
-        final String TRUNCATED_PWD = "secr";
         final BasicAuthHeader AUTH_HEADER =
                 new BasicAuthHeader(NICE_METHOD, BASE64_CRIB);
+        @SuppressWarnings("unused") // Exception will be thrown.
         BasicAuthenticator.BasicCredentials credentials =
                 new BasicAuthenticator.BasicCredentials(
                     AUTH_HEADER.getHeader(), StandardCharsets.UTF_8, true);
-        Assert.assertEquals(USER_NAME, credentials.getUsername());
-        Assert.assertNotSame(PASSWORD, credentials.getPassword());
-        Assert.assertEquals(TRUNCATED_PWD, credentials.getPassword());
     }
 
     /*


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 13/18: Refactor so Principal is never cached in session with cache==false

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit e19a202ee43b6e2a538be5515ae0ab32d8ef112c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Dec 5 23:25:37 2019 +0000

    Refactor so Principal is never cached in session with cache==false
---
 .../catalina/authenticator/AuthenticatorBase.java  |  5 ++--
 .../apache/catalina/authenticator/Constants.java   |  3 ++
 .../catalina/authenticator/FormAuthenticator.java  | 33 ++++++----------------
 3 files changed, 15 insertions(+), 26 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
index 56e8a04..cec4baa 100644
--- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java
+++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
@@ -1135,10 +1135,11 @@ public abstract class AuthenticatorBase extends ValveBase
         }
 
         // Cache the authentication information in our session, if any
-        if (cache) {
-            if (session != null) {
+        if (session != null) {
+            if (cache) {
                 session.setAuthType(authType);
                 session.setPrincipal(principal);
+            } else {
                 if (username != null) {
                     session.setNote(Constants.SESS_USERNAME_NOTE, username);
                 } else {
diff --git a/java/org/apache/catalina/authenticator/Constants.java b/java/org/apache/catalina/authenticator/Constants.java
index d5126cc..f257b4f 100644
--- a/java/org/apache/catalina/authenticator/Constants.java
+++ b/java/org/apache/catalina/authenticator/Constants.java
@@ -82,7 +82,10 @@ public class Constants {
 
     /**
      * The previously authenticated principal (if caching is disabled).
+     *
+     * @deprecated Unused. Will be removed in Tomcat 10.
      */
+    @Deprecated
     public static final String FORM_PRINCIPAL_NOTE = "org.apache.catalina.authenticator.PRINCIPAL";
 
     /**
diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
index 9d5e3f8..f326f77 100644
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
@@ -132,10 +132,6 @@ public class FormAuthenticator
     protected boolean doAuthenticate(Request request, HttpServletResponse response)
             throws IOException {
 
-        if (checkForCachedAuthentication(request, response, true)) {
-            return true;
-        }
-
         // References to objects we will need later
         Session session = null;
         Principal principal = null;
@@ -154,9 +150,8 @@ public class FormAuthenticator
                 }
                 principal = context.getRealm().authenticate(username, password);
                 if (principal != null) {
-                    session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
+                    register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
                     if (!matchRequest(request)) {
-                        register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
                         return true;
                     }
                 }
@@ -173,16 +168,6 @@ public class FormAuthenticator
             if (log.isDebugEnabled()) {
                 log.debug("Restore request from session '" + session.getIdInternal() + "'");
             }
-            principal = (Principal) session.getNote(Constants.FORM_PRINCIPAL_NOTE);
-            register(request, response, principal, HttpServletRequest.FORM_AUTH,
-                     (String) session.getNote(Constants.SESS_USERNAME_NOTE),
-                     (String) session.getNote(Constants.SESS_PASSWORD_NOTE));
-            // If we're caching principals we no longer need the user name
-            // and password in the session, so remove them
-            if (cache) {
-                session.removeNote(Constants.SESS_USERNAME_NOTE);
-                session.removeNote(Constants.SESS_PASSWORD_NOTE);
-            }
             if (restoreRequest(request, session)) {
                 if (log.isDebugEnabled()) {
                     log.debug("Proceed to restored request");
@@ -197,6 +182,12 @@ public class FormAuthenticator
             }
         }
 
+        // This check has to be after the previous check for a matching request
+        // because that matching request may also include a cached Principal.
+        if (checkForCachedAuthentication(request, response, true)) {
+            return true;
+        }
+
         // Acquire references to objects we will need to evaluate
         String contextPath = request.getContextPath();
         String requestURI = request.getDecodedRequestURI();
@@ -283,12 +274,7 @@ public class FormAuthenticator
             return false;
         }
 
-        // Save the authenticated Principal in our session
-        session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
-
-        // Save the username and password as well
-        session.setNote(Constants.SESS_USERNAME_NOTE, username);
-        session.setNote(Constants.SESS_PASSWORD_NOTE, password);
+        register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
 
         // Redirect the user to the original request URI (which will cause
         // the original request to be restored)
@@ -489,7 +475,7 @@ public class FormAuthenticator
         }
 
         // Is there a saved principal?
-        if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null) {
+        if (cache && session.getPrincipal() == null || !cache && request.getPrincipal() == null) {
             return false;
         }
 
@@ -519,7 +505,6 @@ public class FormAuthenticator
         // Retrieve and remove the SavedRequest object from our session
         SavedRequest saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
         session.removeNote(Constants.FORM_REQUEST_NOTE);
-        session.removeNote(Constants.FORM_PRINCIPAL_NOTE);
         if (saved == null) {
             return false;
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 03/18: Merge in FileUpload changes to 2317552 (2019-12-06, 2.0-SNAPSHOT)

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 218ea934fc71a0948c1b2e313e9cf20dede2cc23
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 15:30:48 2019 +0000

    Merge in FileUpload changes to 2317552 (2019-12-06, 2.0-SNAPSHOT)
---
 MERGE.txt                                          |   2 +-
 java/org/apache/catalina/connector/Request.java    |   6 +-
 .../util/http/fileupload/FileItemIterator.java     |  49 +-
 .../util/http/fileupload/FileUploadBase.java       | 702 +--------------------
 .../util/http/fileupload/MultipartStream.java      |  10 +-
 .../util/http/fileupload/disk/DiskFileItem.java    |   3 +-
 .../http/fileupload/impl/FileItemIteratorImpl.java | 339 ++++++++++
 .../http/fileupload/impl/FileItemStreamImpl.java   | 222 +++++++
 .../impl/FileSizeLimitExceededException.java       |  94 +++
 .../fileupload/impl/FileUploadIOException.java     |  63 ++
 .../fileupload/impl/IOFileUploadException.java     |  62 ++
 .../impl/InvalidContentTypeException.java          |  62 ++
 .../util/http/fileupload/impl/SizeException.java   |  75 +++
 .../impl/SizeLimitExceededException.java           |  43 ++
 webapps/docs/changelog.xml                         |   4 +
 15 files changed, 1032 insertions(+), 704 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index b4bd507..893ac89 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -51,7 +51,7 @@ FileUpload
 Sub-tree:
 src/main/java/org/apache/commons/fileupload2
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
-9958ea2426ec5682a7c929a13372c04426ee3818 (2019-08-01)
+2317552993fd5180a84083d599b8cbdb05a07bab (2019-12-06)
 
 Note: Tomcat's copy of fileupload also includes classes copied manually from
       Commons IO.
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index d4b11d5..5d719c1 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -105,10 +105,10 @@ import org.apache.tomcat.util.http.Parameters.FailReason;
 import org.apache.tomcat.util.http.ServerCookie;
 import org.apache.tomcat.util.http.ServerCookies;
 import org.apache.tomcat.util.http.fileupload.FileItem;
-import org.apache.tomcat.util.http.fileupload.FileUploadBase;
-import org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeException;
 import org.apache.tomcat.util.http.fileupload.FileUploadException;
 import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
+import org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException;
+import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
 import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
 import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
 import org.apache.tomcat.util.http.parser.AcceptLanguage;
@@ -2928,7 +2928,7 @@ public class Request implements org.apache.catalina.servlet4preview.http.HttpSer
             } catch (InvalidContentTypeException e) {
                 parameters.setParseFailedReason(FailReason.INVALID_CONTENT_TYPE);
                 partsParseException = new ServletException(e);
-            } catch (FileUploadBase.SizeException e) {
+            } catch (SizeLimitExceededException e) {
                 parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
                 checkSwallowInput();
                 partsParseException = new IllegalStateException(e);
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java b/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
index 4f331ad..9665312 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
@@ -17,12 +17,56 @@
 package org.apache.tomcat.util.http.fileupload;
 
 import java.io.IOException;
+import java.util.List;
+
+import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
+import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
 
 /**
  * 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".
+     */
+    public 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.
+     * <em>Note:</em>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".
+     */
+    public 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 requqest. The value -1 indicates "unlimited".
+     */
+    public 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.
+     * <em>Note:</em> 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".
+     */
+    public void setSizeMax(long pSizeMax);
 
     /**
      * Returns, whether another instance of {@link FileItemStream}
@@ -34,7 +78,7 @@ public interface FileItemIterator {
      * @return True, if one or more additional file items
      *   are available, otherwise false.
      */
-    boolean hasNext() throws FileUploadException, IOException;
+    public boolean hasNext() throws FileUploadException, IOException;
 
     /**
      * Returns the next available {@link FileItemStream}.
@@ -47,6 +91,7 @@ public interface FileItemIterator {
      * @return FileItemStream instance, which provides
      *   access to the next file item.
      */
-    FileItemStream next() throws FileUploadException, IOException;
+    public FileItemStream next() throws FileUploadException, IOException;
 
+    public List<FileItem> getFileItems() throws FileUploadException, IOException;
 }
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
index 486434a..4a68be2 100644
--- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
@@ -17,19 +17,18 @@
 package org.apache.tomcat.util.http.fileupload;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.NoSuchElementException;
 
-import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream;
-import org.apache.tomcat.util.http.fileupload.util.Closeable;
+import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl;
+import org.apache.tomcat.util.http.fileupload.impl.FileItemStreamImpl;
+import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException;
+import org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException;
 import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl;
-import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream;
 import org.apache.tomcat.util.http.fileupload.util.Streams;
 
 
@@ -253,7 +252,7 @@ public abstract class FileUploadBase {
     public FileItemIterator getItemIterator(RequestContext ctx)
     throws FileUploadException, IOException {
         try {
-            return new FileItemIteratorImpl(ctx);
+            return new FileItemIteratorImpl(this, ctx);
         } catch (FileUploadIOException e) {
             // unwrap encapsulated SizeException
             throw (FileUploadException) e.getCause();
@@ -286,7 +285,7 @@ public abstract class FileUploadBase {
             while (iter.hasNext()) {
                 final FileItemStream item = iter.next();
                 // Don't use getName() here to prevent an InvalidFileNameException.
-                final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name;
+                final String fileName = ((FileItemStreamImpl) item).getName();
                 FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(),
                                                    item.isFormField(), fileName);
                 items.add(fileItem);
@@ -363,7 +362,7 @@ public abstract class FileUploadBase {
      *
      * @return The boundary, as a byte array.
      */
-    protected byte[] getBoundary(String contentType) {
+    public byte[] getBoundary(String contentType) {
         ParameterParser parser = new ParameterParser();
         parser.setLowerCaseNames(true);
         // Parameter parser can handle null input
@@ -387,7 +386,7 @@ public abstract class FileUploadBase {
      *
      * @return The file name for the current <code>encapsulation</code>.
      */
-    protected String getFileName(FileItemHeaders headers) {
+    public String getFileName(FileItemHeaders headers) {
         return getFileName(headers.getHeader(CONTENT_DISPOSITION));
     }
 
@@ -429,7 +428,7 @@ public abstract class FileUploadBase {
      *
      * @return The field name for the current <code>encapsulation</code>.
      */
-    protected String getFieldName(FileItemHeaders headers) {
+    public String getFieldName(FileItemHeaders headers) {
         return getFieldName(headers.getHeader(CONTENT_DISPOSITION));
     }
 
@@ -467,7 +466,7 @@ public abstract class FileUploadBase {
      *
      * @return A <code>Map</code> containing the parsed HTTP request headers.
      */
-    protected FileItemHeaders getParsedHeaders(String headerPart) {
+    public FileItemHeaders getParsedHeaders(String headerPart) {
         final int len = headerPart.length();
         FileItemHeadersImpl headers = newFileItemHeaders();
         int start = 0;
@@ -549,687 +548,6 @@ public abstract class FileUploadBase {
     }
 
     /**
-     * The iterator, which is returned by
-     * {@link FileUploadBase#getItemIterator(RequestContext)}.
-     */
-    private class FileItemIteratorImpl implements FileItemIterator {
-
-        /**
-         * Default implementation of {@link FileItemStream}.
-         */
-        class FileItemStreamImpl implements FileItemStream {
-
-            /**
-             * 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 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.
-             */
-            FileItemStreamImpl(String pName, String pFieldName,
-                    String pContentType, boolean pFormField,
-                    long pContentLength) throws IOException {
-                name = pName;
-                fieldName = pFieldName;
-                contentType = pContentType;
-                formField = pFormField;
-                if (fileSizeMax != -1) { // Check if limit is already exceeded
-                    if (pContentLength != -1
-                            && pContentLength > fileSizeMax) {
-                        FileSizeLimitExceededException e =
-                                new FileSizeLimitExceededException(
-                                        String.format("The field %s exceeds its maximum permitted size of %s bytes.",
-                                                       fieldName, Long.valueOf(fileSizeMax)),
-                                        pContentLength, fileSizeMax);
-                        e.setFileName(pName);
-                        e.setFieldName(pFieldName);
-                        throw new FileUploadIOException(e);
-                    }
-                }
-                // OK to construct stream now
-                final ItemInputStream itemStream = multi.newInputStream();
-                InputStream istream = itemStream;
-                if (fileSizeMax != -1) {
-                    istream = new LimitedInputStream(istream, fileSizeMax) {
-                        @Override
-                        protected void raiseError(long pSizeMax, long pCount)
-                                throws IOException {
-                            itemStream.close(true);
-                            FileSizeLimitExceededException e =
-                                new FileSizeLimitExceededException(
-                                    String.format("The field %s exceeds its maximum permitted size of %s bytes.",
-                                           fieldName, Long.valueOf(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 FileItemStream.ItemSkippedException();
-                }
-                return stream;
-            }
-
-            /**
-             * Closes the file item.
-             *
-             * @throws IOException An I/O error occurred.
-             */
-            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(FileItemHeaders pHeaders) {
-                headers = pHeaders;
-            }
-
-        }
-
-        /**
-         * The multi part stream to process.
-         */
-        private final MultipartStream multi;
-
-        /**
-         * The notifier, which used for triggering the
-         * {@link ProgressListener}.
-         */
-        private final MultipartStream.ProgressNotifier notifier;
-
-        /**
-         * The boundary, which separates the various parts.
-         */
-        private final byte[] boundary;
-
-        /**
-         * 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 ctx The request context.
-         * @throws FileUploadException An error occurred while
-         *   parsing the request.
-         * @throws IOException An I/O error occurred.
-         */
-        FileItemIteratorImpl(RequestContext ctx)
-                throws FileUploadException, IOException {
-            if (ctx == null) {
-                throw new NullPointerException("ctx parameter");
-            }
-
-            String contentType = ctx.getContentType();
-            if ((null == contentType)
-                    || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART))) {
-                throw new InvalidContentTypeException(String.format(
-                        "the request doesn't contain a %s or %s stream, content type header is %s",
-                        MULTIPART_FORM_DATA, MULTIPART_MIXED, contentType));
-            }
-
-
-            final long requestSize = ((UploadContext) ctx).contentLength();
-
-            InputStream input; // N.B. this is eventually closed in MultipartStream processing
-            if (sizeMax >= 0) {
-                if (requestSize != -1 && requestSize > sizeMax) {
-                    throw new SizeLimitExceededException(String.format(
-                            "the request was rejected because its size (%s) exceeds the configured maximum (%s)",
-                            Long.valueOf(requestSize), Long.valueOf(sizeMax)),
-                            requestSize, sizeMax);
-                }
-                // N.B. this is eventually closed in MultipartStream processing
-                input = new LimitedInputStream(ctx.getInputStream(), sizeMax) {
-                    @Override
-                    protected void raiseError(long pSizeMax, long pCount)
-                            throws IOException {
-                        FileUploadException ex = new SizeLimitExceededException(
-                        String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
-                               Long.valueOf(pCount), Long.valueOf(pSizeMax)),
-                               pCount, pSizeMax);
-                        throw new FileUploadIOException(ex);
-                    }
-                };
-            } else {
-                input = ctx.getInputStream();
-            }
-
-            String charEncoding = headerEncoding;
-            if (charEncoding == null) {
-                charEncoding = ctx.getCharacterEncoding();
-            }
-
-            boundary = getBoundary(contentType);
-            if (boundary == null) {
-                IOUtils.closeQuietly(input); // avoid possible resource leak
-                throw new FileUploadException("the request was rejected because no multipart boundary was found");
-            }
-
-            notifier = new MultipartStream.ProgressNotifier(listener, requestSize);
-            try {
-                multi = new MultipartStream(input, boundary, notifier);
-            } catch (IllegalArgumentException iae) {
-                IOUtils.closeQuietly(input); // avoid possible resource leak
-                throw new InvalidContentTypeException(
-                        String.format("The boundary specified in the %s header is too long", CONTENT_TYPE), iae);
-            }
-            multi.setHeaderEncoding(charEncoding);
-
-            skipPreamble = true;
-            findNextItem();
-        }
-
-        /**
-         * 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 IOException {
-            if (eof) {
-                return false;
-            }
-            if (currentItem != null) {
-                currentItem.close();
-                currentItem = null;
-            }
-            for (;;) {
-                boolean nextPart;
-                if (skipPreamble) {
-                    nextPart = multi.skipPreamble();
-                } else {
-                    nextPart = multi.readBoundary();
-                }
-                if (!nextPart) {
-                    if (currentFieldName == null) {
-                        // Outer multipart terminated -> No more data
-                        eof = true;
-                        return false;
-                    }
-                    // Inner multipart terminated -> Return to parsing the outer
-                    multi.setBoundary(boundary);
-                    currentFieldName = null;
-                    continue;
-                }
-                FileItemHeaders headers = getParsedHeaders(multi.readHeaders());
-                if (currentFieldName == null) {
-                    // We're parsing the outer multipart
-                    String fieldName = getFieldName(headers);
-                    if (fieldName != null) {
-                        String subContentType = headers.getHeader(CONTENT_TYPE);
-                        if (subContentType != null
-                                &&  subContentType.toLowerCase(Locale.ENGLISH)
-                                        .startsWith(MULTIPART_MIXED)) {
-                            currentFieldName = fieldName;
-                            // Multiple files associated with this field name
-                            byte[] subBoundary = getBoundary(subContentType);
-                            multi.setBoundary(subBoundary);
-                            skipPreamble = true;
-                            continue;
-                        }
-                        String fileName = getFileName(headers);
-                        currentItem = new FileItemStreamImpl(fileName,
-                                fieldName, headers.getHeader(CONTENT_TYPE),
-                                fileName == null, getContentLength(headers));
-                        currentItem.setHeaders(headers);
-                        notifier.noteItem();
-                        itemValid = true;
-                        return true;
-                    }
-                } else {
-                    String fileName = getFileName(headers);
-                    if (fileName != null) {
-                        currentItem = new FileItemStreamImpl(fileName,
-                                currentFieldName,
-                                headers.getHeader(CONTENT_TYPE),
-                                false, getContentLength(headers));
-                        currentItem.setHeaders(headers);
-                        notifier.noteItem();
-                        itemValid = true;
-                        return true;
-                    }
-                }
-                multi.discardBodyData();
-            }
-        }
-
-        private long getContentLength(FileItemHeaders pHeaders) {
-            try {
-                return Long.parseLong(pHeaders.getHeader(CONTENT_LENGTH));
-            } catch (Exception e) {
-                return -1;
-            }
-        }
-
-        /**
-         * Returns, whether another instance of {@link FileItemStream}
-         * is available.
-         *
-         * @throws FileUploadException Parsing or processing the
-         *   file item failed.
-         * @throws IOException Reading the file item failed.
-         * @return True, if one or more additional file items
-         *   are available, otherwise false.
-         */
-        @Override
-        public boolean hasNext() throws FileUploadException, IOException {
-            if (eof) {
-                return false;
-            }
-            if (itemValid) {
-                return true;
-            }
-            try {
-                return findNextItem();
-            } catch (FileUploadIOException e) {
-                // unwrap encapsulated SizeException
-                throw (FileUploadException) e.getCause();
-            }
-        }
-
-        /**
-         * Returns the next available {@link FileItemStream}.
-         *
-         * @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.
-         * @return FileItemStream instance, which provides
-         *   access to the next file item.
-         */
-        @Override
-        public FileItemStream next() throws FileUploadException, IOException {
-            if (eof  ||  (!itemValid && !hasNext())) {
-                throw new NoSuchElementException();
-            }
-            itemValid = false;
-            return currentItem;
-        }
-
-    }
-
-    /**
-     * This exception is thrown for hiding an inner
-     * {@link FileUploadException} in an {@link IOException}.
-     */
-    public static class FileUploadIOException extends IOException {
-
-        private static final long serialVersionUID = -3082868232248803474L;
-
-        public FileUploadIOException() {
-            super();
-        }
-
-        public FileUploadIOException(String message, Throwable cause) {
-            super(message, cause);
-        }
-
-        public FileUploadIOException(String message) {
-            super(message);
-        }
-
-        public FileUploadIOException(Throwable cause) {
-            super(cause);
-        }
-    }
-
-    /**
-     * Thrown to indicate that the request is not a multipart request.
-     */
-    public static class InvalidContentTypeException
-            extends FileUploadException {
-
-        /**
-         * The exceptions UID, for serializing an instance.
-         */
-        private static final long serialVersionUID = -9073026332015646668L;
-
-        /**
-         * Constructs a <code>InvalidContentTypeException</code> with no
-         * detail message.
-         */
-        public InvalidContentTypeException() {
-            super();
-        }
-
-        /**
-         * Constructs an <code>InvalidContentTypeException</code> with
-         * the specified detail message.
-         *
-         * @param message The detail message.
-         */
-        public InvalidContentTypeException(String message) {
-            super(message);
-        }
-
-        /**
-         * Constructs an <code>InvalidContentTypeException</code> with
-         * the specified detail message and cause.
-         *
-         * @param msg The detail message.
-         * @param cause the original cause
-         *
-         * @since 1.3.1
-         */
-        public InvalidContentTypeException(String msg, Throwable cause) {
-            super(msg, cause);
-        }
-    }
-
-    /**
-     * Thrown to indicate an IOException.
-     */
-    public static class IOFileUploadException extends FileUploadException {
-
-        private static final long serialVersionUID = -5858565745868986701L;
-
-        public IOFileUploadException() {
-            super();
-        }
-
-        public IOFileUploadException(String message, Throwable cause) {
-            super(message, cause);
-        }
-
-        public IOFileUploadException(String message) {
-            super(message);
-        }
-
-        public IOFileUploadException(Throwable cause) {
-            super(cause);
-        }
-    }
-
-    /**
-     * This exception is thrown, if a requests permitted size
-     * is exceeded.
-     */
-    public abstract static 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(String message, long actual, 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;
-        }
-
-    }
-
-    /**
-     * Thrown to indicate that the request size exceeds the configured maximum.
-     */
-    public static class SizeLimitExceededException
-            extends SizeException {
-
-        /**
-         * The exceptions UID, for serializing an instance.
-         */
-        private static final long serialVersionUID = -2474893167098052828L;
-
-        /**
-         * Constructs a <code>SizeExceededException</code> 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(String message, long actual,
-                long permitted) {
-            super(message, actual, permitted);
-        }
-
-    }
-
-    /**
-     * Thrown to indicate that A files size exceeds the configured maximum.
-     */
-    public static 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</code> 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(String message, long actual,
-                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(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(String pFieldName) {
-            fieldName = pFieldName;
-        }
-
-    }
-
-    /**
      * Returns the progress listener.
      *
      * @return The progress listener, if any, or null.
diff --git a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
index 351fa02..c3616c3 100644
--- a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
@@ -22,7 +22,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 
-import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileUploadIOException;
+import org.apache.tomcat.util.http.fileupload.impl.FileUploadIOException;
 import org.apache.tomcat.util.http.fileupload.util.Closeable;
 import org.apache.tomcat.util.http.fileupload.util.Streams;
 
@@ -115,7 +115,7 @@ public class MultipartStream {
          * @param pListener The listener to invoke.
          * @param pContentLength The expected content length.
          */
-        ProgressNotifier(ProgressListener pListener, long pContentLength) {
+        public ProgressNotifier(ProgressListener pListener, long pContentLength) {
             listener = pListener;
             contentLength = pContentLength;
         }
@@ -136,7 +136,7 @@ public class MultipartStream {
         /**
          * Called to indicate, that a new file item has been detected.
          */
-        void noteItem() {
+        public void noteItem() {
             ++items;
             notifyListener();
         }
@@ -332,7 +332,7 @@ public class MultipartStream {
      *
      * @see #MultipartStream(InputStream, byte[], int, ProgressNotifier)
      */
-    MultipartStream(InputStream input,
+    public MultipartStream(InputStream input,
             byte[] boundary,
             ProgressNotifier pNotifier) {
         this(input, boundary, DEFAULT_BUFSIZE, pNotifier);
@@ -576,7 +576,7 @@ public class MultipartStream {
      * Creates a new {@link ItemInputStream}.
      * @return A new instance of {@link ItemInputStream}.
      */
-    ItemInputStream newInputStream() {
+    public ItemInputStream newInputStream() {
         return new ItemInputStream();
     }
 
diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
index b94a960..67f5e0c 100644
--- a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
+++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
@@ -546,7 +546,7 @@ public class DiskFileItem
      * Removes the file contents from the temporary storage.
      */
     @Override
-    protected void finalize() {
+    protected void finalize() throws Throwable {
         if (dfos == null || dfos.isInMemory()) {
             return;
         }
@@ -555,6 +555,7 @@ public class DiskFileItem
         if (outputFile != null && outputFile.exists()) {
             outputFile.delete();
         }
+        super.finalize();
     }
 
     /**
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java
new file mode 100644
index 0000000..098e089
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+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 org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileItemHeaders;
+import org.apache.tomcat.util.http.fileupload.FileItemIterator;
+import org.apache.tomcat.util.http.fileupload.FileItemStream;
+import org.apache.tomcat.util.http.fileupload.FileUploadBase;
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+import org.apache.tomcat.util.http.fileupload.MultipartStream;
+import org.apache.tomcat.util.http.fileupload.ProgressListener;
+import org.apache.tomcat.util.http.fileupload.RequestContext;
+import org.apache.tomcat.util.http.fileupload.UploadContext;
+import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream;
+
+/**
+ * The iterator, which is returned by
+ * {@link FileUploadBase#getItemIterator(RequestContext)}.
+ */
+public class FileItemIteratorImpl implements FileItemIterator {
+    private final FileUploadBase fileUploadBase;
+    private final RequestContext ctx;
+    private long sizeMax, fileSizeMax;
+
+
+    @Override
+    public long getSizeMax() {
+        return sizeMax;
+    }
+
+    @Override
+    public void setSizeMax(long sizeMax) {
+        this.sizeMax = sizeMax;
+    }
+
+    @Override
+    public long getFileSizeMax() {
+        return fileSizeMax;
+    }
+
+    @Override
+    public void setFileSizeMax(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 pFileUploadBase Upload instance
+     * @param pRequestContext The request context.
+     * @throws FileUploadException An error occurred while
+     *   parsing the request.
+     * @throws IOException An I/O error occurred.
+     */
+    public FileItemIteratorImpl(FileUploadBase pFileUploadBase, RequestContext pRequestContext)
+            throws FileUploadException, IOException {
+        fileUploadBase = pFileUploadBase;
+        sizeMax = fileUploadBase.getSizeMax();
+        fileSizeMax = fileUploadBase.getFileSizeMax();
+        ctx = pRequestContext;
+        if (ctx == null) {
+            throw new NullPointerException("ctx parameter");
+        }
+
+
+        skipPreamble = true;
+        findNextItem();
+    }
+
+    protected void init(FileUploadBase fileUploadBase, @SuppressWarnings("unused") RequestContext pRequestContext)
+            throws FileUploadException, IOException {
+        String contentType = ctx.getContentType();
+        if ((null == contentType)
+                || (!contentType.toLowerCase(Locale.ENGLISH).startsWith(FileUploadBase.MULTIPART))) {
+            throw new InvalidContentTypeException(
+                    String.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 requestSize = ((UploadContext) ctx).contentLength();
+
+        InputStream input; // N.B. this is eventually closed in MultipartStream processing
+        if (sizeMax >= 0) {
+            if (requestSize != -1 && requestSize > sizeMax) {
+                throw new SizeLimitExceededException(
+                    String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
+                            Long.valueOf(requestSize), Long.valueOf(sizeMax)),
+                           requestSize, sizeMax);
+            }
+            // N.B. this is eventually closed in MultipartStream processing
+            input = new LimitedInputStream(ctx.getInputStream(), sizeMax) {
+                @Override
+                protected void raiseError(long pSizeMax, long pCount)
+                        throws IOException {
+                    FileUploadException ex = new SizeLimitExceededException(
+                    String.format("the request was rejected because its size (%s) exceeds the configured maximum (%s)",
+                            Long.valueOf(pCount), Long.valueOf(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 (IllegalArgumentException iae) {
+            IOUtils.closeQuietly(input); // avoid possible resource leak
+            throw new InvalidContentTypeException(
+                    String.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 (;;) {
+            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;
+            }
+            FileItemHeaders headers = fileUploadBase.getParsedHeaders(multi.readHeaders());
+            if (currentFieldName == null) {
+                // We're parsing the outer multipart
+                String fieldName = fileUploadBase.getFieldName(headers);
+                if (fieldName != null) {
+                    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
+                        byte[] subBoundary = fileUploadBase.getBoundary(subContentType);
+                        multi.setBoundary(subBoundary);
+                        skipPreamble = true;
+                        continue;
+                    }
+                    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 {
+                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(FileItemHeaders pHeaders) {
+        try {
+            return Long.parseLong(pHeaders.getHeader(FileUploadBase.CONTENT_LENGTH));
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Returns, whether another instance of {@link FileItemStream}
+     * is available.
+     *
+     * @throws FileUploadException Parsing or processing the
+     *   file item failed.
+     * @throws IOException Reading the file item failed.
+     * @return True, if one or more additional file items
+     *   are available, otherwise false.
+     */
+    @Override
+    public boolean hasNext() throws FileUploadException, IOException {
+        if (eof) {
+            return false;
+        }
+        if (itemValid) {
+            return true;
+        }
+        try {
+            return findNextItem();
+        } catch (FileUploadIOException e) {
+            // unwrap encapsulated SizeException
+            throw (FileUploadException) e.getCause();
+        }
+    }
+
+    /**
+     * Returns the next available {@link FileItemStream}.
+     *
+     * @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.
+     * @return FileItemStream instance, which provides
+     *   access to the next file item.
+     */
+    @Override
+    public FileItemStream next() throws FileUploadException, IOException {
+        if (eof  ||  (!itemValid && !hasNext())) {
+            throw new NoSuchElementException();
+        }
+        itemValid = false;
+        return currentItem;
+    }
+
+    @Override
+    public List<FileItem> getFileItems() throws FileUploadException, IOException {
+        final List<FileItem> 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;
+    }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
new file mode 100644
index 0000000..29427e6
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.tomcat.util.http.fileupload.FileItemHeaders;
+import org.apache.tomcat.util.http.fileupload.FileItemStream;
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+import org.apache.tomcat.util.http.fileupload.InvalidFileNameException;
+import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream;
+import org.apache.tomcat.util.http.fileupload.util.Closeable;
+import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream;
+import org.apache.tomcat.util.http.fileupload.util.Streams;
+
+
+/**
+ * Default implementation of {@link FileItemStream}.
+ */
+public class FileItemStreamImpl implements FileItemStream {
+    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.
+     */
+    final String name;
+
+    /**
+     * Whether the file item is a form field.
+     */
+    private final boolean formField;
+
+    /**
+     * The file items input stream.
+     */
+    private final InputStream stream;
+
+    /**
+     * Whether the file item was already opened.
+     */
+    private boolean opened;
+
+    /**
+     * The headers, if any.
+     */
+    private FileItemHeaders headers;
+
+    /**
+     * Creates a new instance.
+     * @param pFileItemIterator Iterator for all files in this upload
+     * @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 FileUploadException If an error is encountered processing the request
+     * @throws IOException Creating the file item failed.
+     */
+    public FileItemStreamImpl(FileItemIteratorImpl pFileItemIterator, String pName, String pFieldName,
+            String pContentType, boolean pFormField,
+            long pContentLength) throws FileUploadException, IOException {
+        fileItemIteratorImpl = pFileItemIterator;
+        name = pName;
+        fieldName = pFieldName;
+        contentType = pContentType;
+        formField = pFormField;
+        final long fileSizeMax = fileItemIteratorImpl.getFileSizeMax();
+        if (fileSizeMax != -1) { // Check if limit is already exceeded
+            if (pContentLength != -1
+                    && pContentLength > fileSizeMax) {
+                FileSizeLimitExceededException e =
+                        new FileSizeLimitExceededException(
+                                String.format("The field %s exceeds its maximum permitted size of %s bytes.",
+                                        fieldName, Long.valueOf(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(long pSizeMax, long pCount)
+                        throws IOException {
+                    itemStream.close(true);
+                    FileSizeLimitExceededException e =
+                        new FileSizeLimitExceededException(
+                            String.format("The field %s exceeds its maximum permitted size of %s bytes.",
+                                   fieldName, Long.valueOf(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 (opened) {
+            throw new IllegalStateException(
+                    "The stream was already opened.");
+        }
+        if (((Closeable) stream).isClosed()) {
+            throw new FileItemStream.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(FileItemHeaders pHeaders) {
+        headers = pHeaders;
+    }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java
new file mode 100644
index 0000000..3eaa9d8
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+/**
+ * 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</code> 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(String message, long actual,
+            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(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(String pFieldName) {
+        fieldName = pFieldName;
+    }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java
new file mode 100644
index 0000000..3e71b5c
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+
+/**
+ * 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</code> with the
+     * given cause.
+     *
+     * @param pCause The exceptions cause, if any, or null.
+     */
+    public FileUploadIOException(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.
+     */
+    @SuppressWarnings("sync-override") // Field is final
+    @Override
+    public Throwable getCause() {
+        return cause;
+    }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java b/java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java
new file mode 100644
index 0000000..90f259d
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+
+/**
+ * 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(String pMsg, IOException pException) {
+        super(pMsg);
+        cause = pException;
+    }
+
+    /**
+     * Returns the exceptions cause.
+     *
+     * @return The exceptions cause, if any, or null.
+     */
+    @SuppressWarnings("sync-override") // Field is final
+    @Override
+    public Throwable getCause() {
+        return cause;
+    }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java b/java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java
new file mode 100644
index 0000000..295597b
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+import org.apache.tomcat.util.http.fileupload.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</code> with no
+     * detail message.
+     */
+    public InvalidContentTypeException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InvalidContentTypeException</code> with
+     * the specified detail message.
+     *
+     * @param message The detail message.
+     */
+    public InvalidContentTypeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an <code>InvalidContentTypeException</code> with
+     * the specified detail message and cause.
+     *
+     * @param msg The detail message.
+     * @param cause the original cause
+     *
+     * @since 1.3.1
+     */
+    public InvalidContentTypeException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java b/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
new file mode 100644
index 0000000..4852795
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+import org.apache.tomcat.util.http.fileupload.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(String message, long actual, 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;
+    }
+
+}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java b/java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java
new file mode 100644
index 0000000..668e99b
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.impl;
+
+/**
+ * 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</code> 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(String message, long actual,
+            long permitted) {
+        super(message, actual, permitted);
+    }
+
+}
\ No newline at end of file
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 37e01d6..9b8c487 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -209,6 +209,10 @@
         Update the internal fork of Apache Commons Codec to 9637dd4 (2019-12-06,
         1.14-SNAPSHOT). Code clean-up and a fix for CODEC-265. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons FileUpload to 2317552
+        (2019-12-06, 2.0-SNAPSHOT). Refactoring. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 14/18: Harden the FORM authentication process

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit e8ae801192b3b07afdffeb0c653eb2abe4808e9e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Dec 5 23:01:42 2019 +0000

    Harden the FORM authentication process
    
    When the session ID is configured to change on authentication, track the
    expected session ID through the authentication process and ensure that
    the expected value is seen at each stage.
---
 .../catalina/authenticator/AuthenticatorBase.java    |  6 +++++-
 .../org/apache/catalina/authenticator/Constants.java |  6 ++++++
 .../catalina/authenticator/FormAuthenticator.java    | 20 +++++++++++++++++++-
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
index cec4baa..f35fbd6 100644
--- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java
+++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
@@ -1128,7 +1128,11 @@ public abstract class AuthenticatorBase extends ValveBase
             // If the principal is null then this is a logout. No need to change
             // the session ID. See BZ 59043.
             if (getChangeSessionIdOnAuthentication() && principal != null) {
-                changeSessionID(request, session);
+                String newSessionId = changeSessionID(request, session);
+                // If the current session ID is being tracked, update it.
+                if (session.getNote(Constants.SESSION_ID_NOTE) != null) {
+                    session.setNote(Constants.SESSION_ID_NOTE, newSessionId);
+                }
             }
         } else if (alwaysUseSession) {
             session = request.getSessionInternal(true);
diff --git a/java/org/apache/catalina/authenticator/Constants.java b/java/org/apache/catalina/authenticator/Constants.java
index f257b4f..66f2a49 100644
--- a/java/org/apache/catalina/authenticator/Constants.java
+++ b/java/org/apache/catalina/authenticator/Constants.java
@@ -58,6 +58,12 @@ public class Constants {
     // ---------------------------------------------------------- Session Notes
 
     /**
+     * The session id used as a CSRF marker when redirecting a user's request.
+     */
+    public static final String SESSION_ID_NOTE = "org.apache.catalina.authenticator.SESSION_ID";
+
+
+    /**
      * If the <code>cache</code> property of our authenticator is set, and
      * the current request is part of a session, authentication information
      * will be cached to avoid the need for repeated calls to
diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
index f326f77..e9b9839 100644
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
@@ -253,6 +253,14 @@ public class FormAuthenticator
         if (session == null) {
             session = request.getSessionInternal(false);
         }
+        if (session != null && getChangeSessionIdOnAuthentication()) {
+            // Does session id match?
+            String expectedSessionId = (String) session.getNote(Constants.SESSION_ID_NOTE);
+            if (expectedSessionId == null || !expectedSessionId.equals(request.getRequestedSessionId())) {
+                session.expire();
+                session = null;
+            }
+        }
         if (session == null) {
             if (containerLog.isDebugEnabled()) {
                 containerLog.debug("User took so long to log on the session expired");
@@ -382,7 +390,8 @@ public class FormAuthenticator
         if (getChangeSessionIdOnAuthentication()) {
             Session session = request.getSessionInternal(false);
             if (session != null) {
-                changeSessionID(request, session);
+                String newSessionId = changeSessionID(request, session);
+                session.setNote(Constants.SESSION_ID_NOTE, newSessionId);
             }
         }
 
@@ -479,6 +488,14 @@ public class FormAuthenticator
             return false;
         }
 
+        // Does session id match?
+        if (getChangeSessionIdOnAuthentication()) {
+            String expectedSessionId = (String) session.getNote(Constants.SESSION_ID_NOTE);
+            if (expectedSessionId == null || !expectedSessionId.equals(request.getRequestedSessionId())) {
+                return false;
+            }
+        }
+
         // Does the request URI match?
         String decodedRequestURI = request.getDecodedRequestURI();
         if (decodedRequestURI == null) {
@@ -505,6 +522,7 @@ public class FormAuthenticator
         // Retrieve and remove the SavedRequest object from our session
         SavedRequest saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
         session.removeNote(Constants.FORM_REQUEST_NOTE);
+        session.removeNote(Constants.SESSION_ID_NOTE);
         if (saved == null) {
             return false;
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 11/18: Clean-up prior to some refactoring.

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 38ec82c0435f87e3daffa408305cc70e84333fba
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Dec 5 20:00:02 2019 +0000

    Clean-up prior to some refactoring.
---
 .../catalina/authenticator/FormAuthenticator.java  | 57 ++++++++--------------
 1 file changed, 19 insertions(+), 38 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
index 1b54ddd..8f4268b 100644
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
@@ -147,22 +147,17 @@ public class FormAuthenticator
             if (log.isDebugEnabled()) {
                 log.debug("Checking for reauthenticate in session " + session);
             }
-            String username =
-                (String) session.getNote(Constants.SESS_USERNAME_NOTE);
-            String password =
-                (String) session.getNote(Constants.SESS_PASSWORD_NOTE);
-            if ((username != null) && (password != null)) {
+            String username = (String) session.getNote(Constants.SESS_USERNAME_NOTE);
+            String password = (String) session.getNote(Constants.SESS_PASSWORD_NOTE);
+            if (username != null && password != null) {
                 if (log.isDebugEnabled()) {
                     log.debug("Reauthenticating username '" + username + "'");
                 }
-                principal =
-                    context.getRealm().authenticate(username, password);
+                principal = context.getRealm().authenticate(username, password);
                 if (principal != null) {
                     session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
                     if (!matchRequest(request)) {
-                        register(request, response, principal,
-                                HttpServletRequest.FORM_AUTH,
-                                username, password);
+                        register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
                         return true;
                     }
                 }
@@ -177,16 +172,13 @@ public class FormAuthenticator
         if (matchRequest(request)) {
             session = request.getSessionInternal(true);
             if (log.isDebugEnabled()) {
-                log.debug("Restore request from session '"
-                          + session.getIdInternal()
-                          + "'");
+                log.debug("Restore request from session '" + session.getIdInternal() + "'");
             }
-            principal = (Principal)
-                session.getNote(Constants.FORM_PRINCIPAL_NOTE);
+            principal = (Principal) session.getNote(Constants.FORM_PRINCIPAL_NOTE);
             register(request, response, principal, HttpServletRequest.FORM_AUTH,
                      (String) session.getNote(Constants.SESS_USERNAME_NOTE),
                      (String) session.getNote(Constants.SESS_PASSWORD_NOTE));
-            // If we're caching principals we no longer need the username
+            // If we're caching principals we no longer need the user name
             // and password in the session, so remove them
             if (cache) {
                 session.removeNote(Constants.SESS_USERNAME_NOTE);
@@ -211,9 +203,7 @@ public class FormAuthenticator
         String requestURI = request.getDecodedRequestURI();
 
         // Is this the action request from the login page?
-        boolean loginAction =
-            requestURI.startsWith(contextPath) &&
-            requestURI.endsWith(Constants.FORM_ACTION);
+        boolean loginAction = requestURI.startsWith(contextPath) && requestURI.endsWith(Constants.FORM_ACTION);
 
         LoginConfig config = context.getLoginConfig();
 
@@ -241,8 +231,7 @@ public class FormAuthenticator
                 saveRequest(request, session);
             } catch (IOException ioe) {
                 log.debug("Request body too big to save during authentication");
-                response.sendError(HttpServletResponse.SC_FORBIDDEN,
-                        sm.getString("authenticator.requestBodyTooBig"));
+                response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("authenticator.requestBodyTooBig"));
                 return false;
             }
             forwardToLoginPage(request, response, config);
@@ -276,12 +265,11 @@ public class FormAuthenticator
         }
         if (session == null) {
             if (containerLog.isDebugEnabled()) {
-                containerLog.debug
-                    ("User took so long to log on the session expired");
+                containerLog.debug("User took so long to log on the session expired");
             }
             if (landingPage == null) {
-                response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT,
-                        sm.getString("authenticator.sessionExpired"));
+                response.sendError(
+                        HttpServletResponse.SC_REQUEST_TIMEOUT, sm.getString("authenticator.sessionExpired"));
             } else {
                 // Make the authenticator think the user originally requested
                 // the landing page
@@ -290,8 +278,7 @@ public class FormAuthenticator
                 saved.setMethod("GET");
                 saved.setRequestURI(uri);
                 saved.setDecodedRequestURI(uri);
-                request.getSessionInternal(true).setNote(
-                        Constants.FORM_REQUEST_NOTE, saved);
+                request.getSessionInternal(true).setNote(Constants.FORM_REQUEST_NOTE, saved);
                 response.sendRedirect(response.encodeRedirectURL(uri));
             }
             return false;
@@ -312,8 +299,7 @@ public class FormAuthenticator
         }
         if (requestURI == null) {
             if (landingPage == null) {
-                response.sendError(HttpServletResponse.SC_BAD_REQUEST,
-                        sm.getString("authenticator.formlogin"));
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, sm.getString("authenticator.formlogin"));
             } else {
                 // Make the authenticator think the user originally requested
                 // the landing page
@@ -331,15 +317,12 @@ public class FormAuthenticator
             Response internalResponse = request.getResponse();
             String location = response.encodeRedirectURL(requestURI);
             if ("HTTP/1.1".equals(request.getProtocol())) {
-                internalResponse.sendRedirect(location,
-                        HttpServletResponse.SC_SEE_OTHER);
+                internalResponse.sendRedirect(location, HttpServletResponse.SC_SEE_OTHER);
             } else {
-                internalResponse.sendRedirect(location,
-                        HttpServletResponse.SC_FOUND);
+                internalResponse.sendRedirect(location, HttpServletResponse.SC_FOUND);
             }
         }
         return false;
-
     }
 
 
@@ -503,8 +486,7 @@ public class FormAuthenticator
         }
 
         // Is there a saved request?
-        SavedRequest sreq =
-                (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
+        SavedRequest sreq = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
         if (sreq == null) {
             return false;
         }
@@ -538,8 +520,7 @@ public class FormAuthenticator
             throws IOException {
 
         // Retrieve and remove the SavedRequest object from our session
-        SavedRequest saved = (SavedRequest)
-            session.getNote(Constants.FORM_REQUEST_NOTE);
+        SavedRequest saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
         session.removeNote(Constants.FORM_REQUEST_NOTE);
         session.removeNote(Constants.FORM_PRINCIPAL_NOTE);
         if (saved == null) {


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 16/18: Update changelog

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 98c7c55d03fb24c42d07d3afde59a19fd3438a5c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 21:14:06 2019 +0000

    Update changelog
---
 webapps/docs/changelog.xml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 87e9e84..5c9cda8 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -103,6 +103,11 @@
         and refactor loops in <code>FileStore</code> to use the ForEach style.
         Pull request provided by Govinda Sakhare. (markt)
       </scode>
+      <fix>
+        Refactor FORM authentication to reduce duplicate code and to ensure that
+        the authenticated Principal is not cached in the session when caching is
+        disabled. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 02/18: Merge in Codec changes to 9637dd4 (2019-12-06, 1.14-SNAPSHOT)

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 99382b7cb94b539ca4b22f43cd1b638dc0241215
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 14:29:01 2019 +0000

    Merge in Codec changes to 9637dd4 (2019-12-06, 1.14-SNAPSHOT)
---
 MERGE.txt                                          |   2 +-
 .../apache/tomcat/util/codec/binary/Base64.java    |  28 +++---
 .../tomcat/util/codec/binary/BaseNCodec.java       | 100 +++++++++++++++++----
 webapps/docs/changelog.xml                         |   4 +
 4 files changed, 107 insertions(+), 27 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index f4fb1f8..b4bd507 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -43,7 +43,7 @@ Codec
 Sub-tree:
 src/main/java/org/apache/commons/codec
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
-3ebef4ad92e31697fb52ca7cc71904c68654c2c8 (2019-08-01)
+9637dd44fa0e2d5a6ddb45791e3cd78298842d95 (2019-12-06)
 Note: Only classes required for Base64 encoding/decoding. The rest are removed.
 
 FileUpload
diff --git a/java/org/apache/tomcat/util/codec/binary/Base64.java b/java/org/apache/tomcat/util/codec/binary/Base64.java
index da1487f..ab89854 100644
--- a/java/org/apache/tomcat/util/codec/binary/Base64.java
+++ b/java/org/apache/tomcat/util/codec/binary/Base64.java
@@ -139,6 +139,10 @@ public class Base64 extends BaseNCodec {
      */
     /** Mask used to extract 6 bits, used when encoding */
     private static final int MASK_6BITS = 0x3f;
+    /** Mask used to extract 4 bits, used when decoding final trailing character. */
+    private static final int MASK_4BITS = 0xf;
+    /** Mask used to extract 2 bits, used when decoding final trailing character. */
+    private static final int MASK_2BITS = 0x3;
 
     // The static final fields above are used for the original static byte[] methods on Base64.
     // The private member fields below are used with the new streaming approach, which requires
@@ -483,12 +487,12 @@ public class Base64 extends BaseNCodec {
                     // TODO not currently tested; perhaps it is impossible?
                     break;
                 case 2 : // 12 bits = 8 + 4
-                    validateCharacter(4, context);
+                    validateCharacter(MASK_4BITS, context);
                     context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
                     buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
                     break;
                 case 3 : // 18 bits = 8 + 8 + 2
-                    validateCharacter(2, context);
+                    validateCharacter(MASK_2BITS, context);
                     context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
                     buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
                     buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
@@ -792,20 +796,22 @@ public class Base64 extends BaseNCodec {
 
 
     /**
-     * <p>
-     * Validates whether the character is possible in the context of the set of possible base 64 values.
-     * </p>
+     * Validates whether decoding the final trailing character is possible in the context
+     * of the set of possible base 64 values.
+     *
+     * <p>The character is valid if the lower bits within the provided mask are zero. This
+     * is used to test the final trailing base-64 digit is zero in the bits that will be discarded.
      *
-     * @param numBitsToDrop number of least significant bits to check
+     * @param emptyBitsMask The mask of the lower bits that should be empty
      * @param context the context to be used
      *
      * @throws IllegalArgumentException if the bits being checked contain any non-zero value
      */
-    private long validateCharacter(final int numBitsToDrop, final Context context) {
-        if ((context.ibitWorkArea & numBitsToDrop) != 0) {
-        throw new IllegalArgumentException(
-            "Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value");
+    private static void validateCharacter(final int emptyBitsMask, final Context context) {
+        if ((context.ibitWorkArea & emptyBitsMask) != 0) {
+            throw new IllegalArgumentException(
+                "Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value. " +
+                "Expected the discarded bits to be zero.");
         }
-        return context.ibitWorkArea >> numBitsToDrop;
     }
 }
diff --git a/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java b/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java
index 4dbe84a..0e2d1ad 100644
--- a/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java
+++ b/java/org/apache/tomcat/util/codec/binary/BaseNCodec.java
@@ -141,6 +141,18 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
      */
     private static final int DEFAULT_BUFFER_SIZE = 128;
 
+    /**
+     * The maximum size buffer to allocate.
+     *
+     * <p>This is set to the same size used in the JDK {@code java.util.ArrayList}:</p>
+     * <blockquote>
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit.
+     * </blockquote>
+     */
+    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
     /** Mask used to extract 8 bits, used in decoding bytes */
     protected static final int MASK_8BITS = 0xff;
 
@@ -170,7 +182,7 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
     private final int chunkSeparatorLength;
 
     /**
-     * Note <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
+     * Note <code>lineLength</code> is rounded down to the nearest multiple of the encoded block size.
      * If <code>chunkSeparatorLength</code> is zero, then chunking is disabled.
      * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
      * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
@@ -183,7 +195,7 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
     }
 
     /**
-     * Note <code>lineLength</code> is rounded down to the nearest multiple of {@link #encodedBlockSize}
+     * Note <code>lineLength</code> is rounded down to the nearest multiple of the encoded block size.
      * If <code>chunkSeparatorLength</code> is zero, then chunking is disabled.
      * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
      * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
@@ -225,7 +237,7 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
     /**
      * Get the default buffer size. Can be overridden.
      *
-     * @return {@link #DEFAULT_BUFFER_SIZE}
+     * @return the default buffer size.
      */
     protected int getDefaultBufferSize() {
         return DEFAULT_BUFFER_SIZE;
@@ -234,18 +246,69 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
     /**
      * Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}.
      * @param context the context to be used
+     * @param minCapacity the minimum required capacity
+     * @return the resized byte[] buffer
+     * @throws OutOfMemoryError if the {@code minCapacity} is negative
      */
-    private byte[] resizeBuffer(final Context context) {
-        if (context.buffer == null) {
-            context.buffer = new byte[getDefaultBufferSize()];
-            context.pos = 0;
-            context.readPos = 0;
-        } else {
-            final byte[] b = new byte[context.buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
-            System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
-            context.buffer = b;
+    private static byte[] resizeBuffer(final Context context, final int minCapacity) {
+        // Overflow-conscious code treats the min and new capacity as unsigned.
+        final int oldCapacity = context.buffer.length;
+        int newCapacity = oldCapacity * DEFAULT_BUFFER_RESIZE_FACTOR;
+        if (compareUnsigned(newCapacity, minCapacity) < 0) {
+            newCapacity = minCapacity;
         }
-        return context.buffer;
+        if (compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) {
+            newCapacity = createPositiveCapacity(minCapacity);
+        }
+
+        final byte[] b = new byte[newCapacity];
+        System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
+        context.buffer = b;
+        return b;
+    }
+
+    /**
+     * Compares two {@code int} values numerically treating the values
+     * as unsigned. Taken from JDK 1.8.
+     *
+     * <p>TODO: Replace with JDK 1.8 Integer::compareUnsigned(int, int).</p>
+     *
+     * @param  x the first {@code int} to compare
+     * @param  y the second {@code int} to compare
+     * @return the value {@code 0} if {@code x == y}; a value less
+     *         than {@code 0} if {@code x < y} as unsigned values; and
+     *         a value greater than {@code 0} if {@code x > y} as
+     *         unsigned values
+     */
+    private static int compareUnsigned(int x, int y) {
+        return Integer.compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE);
+    }
+
+    /**
+     * Create a positive capacity at least as large the minimum required capacity.
+     * If the minimum capacity is negative then this throws an OutOfMemoryError as no array
+     * can be allocated.
+     *
+     * @param minCapacity the minimum capacity
+     * @return the capacity
+     * @throws OutOfMemoryError if the {@code minCapacity} is negative
+     */
+    private static int createPositiveCapacity(int minCapacity) {
+        if (minCapacity < 0) {
+            // overflow
+            throw new OutOfMemoryError("Unable to allocate array size: " + (minCapacity & 0xffffffffL));
+        }
+        // This is called when we require buffer expansion to a very big array.
+        // Use the conservative maximum buffer size if possible, otherwise the biggest required.
+        //
+        // Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE.
+        // This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full
+        // Integer.MAX_VALUE length array.
+        // The result is that we may have to allocate an array of this size more than once if
+        // the capacity must be expanded again.
+        return (minCapacity > MAX_BUFFER_SIZE) ?
+            minCapacity :
+            MAX_BUFFER_SIZE;
     }
 
     /**
@@ -256,8 +319,15 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
      * @return the buffer
      */
     protected byte[] ensureBufferSize(final int size, final Context context){
-        if ((context.buffer == null) || (context.buffer.length < context.pos + size)){
-            return resizeBuffer(context);
+        if (context.buffer == null) {
+            context.buffer = new byte[getDefaultBufferSize()];
+            context.pos = 0;
+            context.readPos = 0;
+
+            // Overflow-conscious:
+            // x + y > z  ==  x + y - z > 0
+        } else if (context.pos + size - context.buffer.length > 0) {
+            return resizeBuffer(context, context.pos + size);
         }
         return context.buffer;
     }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index c2fc5de..37e01d6 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -205,6 +205,10 @@
         Update the internal fork of Apache Commons BCEL to ff6941e (2019-12-06,
         6.4.2-dev). Code clean-up only. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons Codec to 9637dd4 (2019-12-06,
+        1.14-SNAPSHOT). Code clean-up and a fix for CODEC-265. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 06/18: Fix Findbugs warnings

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b9469e8ec5fe04ae251f379bfd1638a7e0fe27f1
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 16:42:32 2019 +0000

    Fix Findbugs warnings
---
 test/org/apache/catalina/session/FileStoreTest.java | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/test/org/apache/catalina/session/FileStoreTest.java b/test/org/apache/catalina/session/FileStoreTest.java
index f2555de..c827562 100644
--- a/test/org/apache/catalina/session/FileStoreTest.java
+++ b/test/org/apache/catalina/session/FileStoreTest.java
@@ -60,9 +60,15 @@ public class FileStoreTest {
     @Before
     public void beforeEachTest() throws IOException {
         fileStore.setDirectory(SESS_TEMPPATH);
-        dir.mkdir();
-        file1.createNewFile();
-        file2.createNewFile();
+        if (!dir.mkdir()) {
+            Assert.fail();
+        }
+        if (!file1.createNewFile()) {
+            Assert.fail();
+        }
+        if (!file2.createNewFile()) {
+            Assert.fail();
+        }
     }
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 08/18: Fix FileUpload

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 1a5e42b14ee53981a5a2552c75a6299dfc9603fd
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 18:59:59 2019 +0000

    Fix FileUpload
---
 java/org/apache/catalina/connector/Request.java                     | 4 ++--
 java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 5d719c1..bb4039d 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -108,7 +108,7 @@ import org.apache.tomcat.util.http.fileupload.FileItem;
 import org.apache.tomcat.util.http.fileupload.FileUploadException;
 import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
 import org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException;
-import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException;
+import org.apache.tomcat.util.http.fileupload.impl.SizeException;
 import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
 import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
 import org.apache.tomcat.util.http.parser.AcceptLanguage;
@@ -2928,7 +2928,7 @@ public class Request implements org.apache.catalina.servlet4preview.http.HttpSer
             } catch (InvalidContentTypeException e) {
                 parameters.setParseFailedReason(FailReason.INVALID_CONTENT_TYPE);
                 partsParseException = new ServletException(e);
-            } catch (SizeLimitExceededException e) {
+            } catch (SizeException e) {
                 parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
                 checkSwallowInput();
                 partsParseException = new IllegalStateException(e);
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java b/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
index 4852795..7928f2d 100644
--- a/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
@@ -22,7 +22,7 @@ import org.apache.tomcat.util.http.fileupload.FileUploadException;
  * This exception is thrown, if a requests permitted size
  * is exceeded.
  */
-abstract class SizeException extends FileUploadException {
+public abstract class SizeException extends FileUploadException {
 
     /**
      * Serial version UID, being used, if serialized.


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 07/18: Remove unused code reported by SpotBugs

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit b167af1b37c655e5c1287e26375b3fd85caaff0a
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 16:49:52 2019 +0000

    Remove unused code reported by SpotBugs
---
 .../tomcat/util/http/fileupload/impl/FileItemStreamImpl.java     | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
index 29427e6..06bf33e 100644
--- a/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
@@ -61,11 +61,6 @@ public class FileItemStreamImpl implements FileItemStream {
     private final InputStream stream;
 
     /**
-     * Whether the file item was already opened.
-     */
-    private boolean opened;
-
-    /**
      * The headers, if any.
      */
     private FileItemHeaders headers;
@@ -180,10 +175,6 @@ public class FileItemStreamImpl implements FileItemStream {
      */
     @Override
     public InputStream openStream() throws IOException {
-        if (opened) {
-            throw new IllegalStateException(
-                    "The stream was already opened.");
-        }
         if (((Closeable) stream).isClosed()) {
             throw new FileItemStream.ItemSkippedException();
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 12/18: Refactor change of session ID to reduce duplicate code

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 0fded7df4bcc345b0063993650a0dfcbf8cbb04a
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Dec 5 23:11:03 2019 +0000

    Refactor change of session ID to reduce duplicate code
---
 .../catalina/authenticator/AuthenticatorBase.java  | 29 ++++++++++++----------
 .../catalina/authenticator/FormAuthenticator.java  |  5 +---
 2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
index 2b5a502..56e8a04 100644
--- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java
+++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java
@@ -46,7 +46,6 @@ import org.apache.catalina.Container;
 import org.apache.catalina.Context;
 import org.apache.catalina.Globals;
 import org.apache.catalina.LifecycleException;
-import org.apache.catalina.Manager;
 import org.apache.catalina.Realm;
 import org.apache.catalina.Session;
 import org.apache.catalina.TomcatPrincipal;
@@ -1128,18 +1127,8 @@ public abstract class AuthenticatorBase extends ValveBase
         if (session != null) {
             // If the principal is null then this is a logout. No need to change
             // the session ID. See BZ 59043.
-            if (changeSessionIdOnAuthentication && principal != null) {
-                String oldId = null;
-                if (log.isDebugEnabled()) {
-                    oldId = session.getId();
-                }
-                Manager manager = request.getContext().getManager();
-                manager.changeSessionId(session);
-                request.changeSessionId(session.getId());
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("authenticator.changeSessionId",
-                            oldId, session.getId()));
-                }
+            if (getChangeSessionIdOnAuthentication() && principal != null) {
+                changeSessionID(request, session);
             }
         } else if (alwaysUseSession) {
             session = request.getSessionInternal(true);
@@ -1226,6 +1215,20 @@ public abstract class AuthenticatorBase extends ValveBase
 
     }
 
+
+    protected String changeSessionID(Request request, Session session) {
+        String oldId = null;
+        if (log.isDebugEnabled()) {
+            oldId = session.getId();
+        }
+        String newId = request.changeSessionId();
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("authenticator.changeSessionId", oldId, newId));
+        }
+        return newId;
+    }
+
+
     @Override
     public void login(String username, String password, Request request) throws ServletException {
         Principal principal = doLogin(request, username, password);
diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
index 8f4268b..9d5e3f8 100644
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
@@ -28,7 +28,6 @@ import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.catalina.Manager;
 import org.apache.catalina.Realm;
 import org.apache.catalina.Session;
 import org.apache.catalina.connector.Request;
@@ -397,9 +396,7 @@ public class FormAuthenticator
         if (getChangeSessionIdOnAuthentication()) {
             Session session = request.getSessionInternal(false);
             if (session != null) {
-                Manager manager = request.getContext().getManager();
-                manager.changeSessionId(session);
-                request.changeSessionId(session.getId());
+                changeSessionID(request, session);
             }
         }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 10/18: Clean-up. No functional change.

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 17ffce9c91f76d08ea63c8aae19e654c5014cdb5
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Dec 5 19:59:47 2019 +0000

    Clean-up. No functional change.
---
 .../apache/catalina/authenticator/Constants.java   | 44 ++++++----------------
 1 file changed, 11 insertions(+), 33 deletions(-)

diff --git a/java/org/apache/catalina/authenticator/Constants.java b/java/org/apache/catalina/authenticator/Constants.java
index 5e75c2c..d5126cc 100644
--- a/java/org/apache/catalina/authenticator/Constants.java
+++ b/java/org/apache/catalina/authenticator/Constants.java
@@ -14,11 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-
 package org.apache.catalina.authenticator;
 
-
 public class Constants {
     // Authentication methods for login configuration
     // Servlet spec schemes are defined in HttpServletRequest
@@ -33,23 +30,18 @@ public class Constants {
     // SPNEGO authentication constants
     public static final String KRB5_CONF_PROPERTY = "java.security.krb5.conf";
     public static final String DEFAULT_KRB5_CONF = "conf/krb5.ini";
-    public static final String JAAS_CONF_PROPERTY =
-            "java.security.auth.login.config";
+    public static final String JAAS_CONF_PROPERTY = "java.security.auth.login.config";
     public static final String DEFAULT_JAAS_CONF = "conf/jaas.conf";
-    public static final String DEFAULT_LOGIN_MODULE_NAME =
-        "com.sun.security.jgss.krb5.accept";
+    public static final String DEFAULT_LOGIN_MODULE_NAME = "com.sun.security.jgss.krb5.accept";
     /**
      * @deprecated Unused. Will be removed in Tomcat 9.
      */
     @Deprecated
-    public static final String USE_SUBJECT_CREDS_ONLY_PROPERTY =
-            "javax.security.auth.useSubjectCredsOnly";
+    public static final String USE_SUBJECT_CREDS_ONLY_PROPERTY = "javax.security.auth.useSubjectCredsOnly";
 
     // Cookie name for single sign on support
-    public static final String SINGLE_SIGN_ON_COOKIE =
-        System.getProperty(
-                "org.apache.catalina.authenticator.Constants.SSO_SESSION_COOKIE_NAME",
-                "JSESSIONIDSSO");
+    public static final String SINGLE_SIGN_ON_COOKIE = System.getProperty(
+            "org.apache.catalina.authenticator.Constants.SSO_SESSION_COOKIE_NAME", "JSESSIONIDSSO");
 
 
     // --------------------------------------------------------- Request Notes
@@ -58,17 +50,13 @@ public class Constants {
      * The notes key to track the single-sign-on identity with which this
      * request is associated.
      */
-    public static final String REQ_SSOID_NOTE =
-            "org.apache.catalina.request.SSOID";
+    public static final String REQ_SSOID_NOTE = "org.apache.catalina.request.SSOID";
 
-
-    public static final String REQ_JASPIC_SUBJECT_NOTE =
-            "org.apache.catalina.authenticator.jaspic.SUBJECT";
+    public static final String REQ_JASPIC_SUBJECT_NOTE = "org.apache.catalina.authenticator.jaspic.SUBJECT";
 
 
     // ---------------------------------------------------------- Session Notes
 
-
     /**
      * If the <code>cache</code> property of our authenticator is set, and
      * the current request is part of a session, authentication information
@@ -76,19 +64,15 @@ public class Constants {
      * <code>Realm.authenticate()</code>, under the following keys:
      */
 
-
     /**
      * The notes key for the password used to authenticate this user.
      */
-    public static final String SESS_PASSWORD_NOTE =
-      "org.apache.catalina.session.PASSWORD";
-
+    public static final String SESS_PASSWORD_NOTE = "org.apache.catalina.session.PASSWORD";
 
     /**
      * The notes key for the username used to authenticate this user.
      */
-    public static final String SESS_USERNAME_NOTE =
-      "org.apache.catalina.session.USERNAME";
+    public static final String SESS_USERNAME_NOTE = "org.apache.catalina.session.USERNAME";
 
 
     /**
@@ -96,20 +80,14 @@ public class Constants {
      * cache required information prior to the completion of authentication.
      */
 
-
     /**
      * The previously authenticated principal (if caching is disabled).
      */
-    public static final String FORM_PRINCIPAL_NOTE =
-        "org.apache.catalina.authenticator.PRINCIPAL";
-
+    public static final String FORM_PRINCIPAL_NOTE = "org.apache.catalina.authenticator.PRINCIPAL";
 
     /**
      * The original request information, to which the user will be
      * redirected if authentication succeeds.
      */
-    public static final String FORM_REQUEST_NOTE =
-        "org.apache.catalina.authenticator.REQUEST";
-
-
+    public static final String FORM_REQUEST_NOTE = "org.apache.catalina.authenticator.REQUEST";
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org