From 44d05d75d696ca10ce251e4e370511e38f20ae75 Mon Sep 17 00:00:00 2001
From: Mark Thomas <markt@apache.org>
Date: Thu, 5 Oct 2023 20:52:46 +0100
Subject: [PATCH] Improve handling of failures during recycle() methods

---
 .../catalina/connector/LocalStrings.properties    |  1 +
 java/org/apache/catalina/connector/Request.java   |  7 ++++---
 .../catalina/core/ApplicationHttpRequest.java     |  8 +++++++-
 .../apache/catalina/core/LocalStrings.properties  |  1 +
 .../catalina/core/LocalStrings_cs.properties      |  2 ++
 .../catalina/core/LocalStrings_es.properties      |  2 ++
 .../catalina/core/LocalStrings_fr.properties      |  1 +
 .../catalina/core/LocalStrings_ja.properties      |  1 +
 .../catalina/core/LocalStrings_ko.properties      |  1 +
 .../catalina/core/LocalStrings_zh_CN.properties   |  1 +
 java/org/apache/tomcat/util/buf/B2CConverter.java | 11 ++++++++++-
 java/org/apache/tomcat/util/buf/C2BConverter.java | 15 ++++++++++++++-
 .../tomcat/util/buf/LocalStrings.properties       |  3 +++
 webapps/docs/changelog.xml                        |  4 ++++
 14 files changed, 52 insertions(+), 6 deletions(-)

Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/connector/LocalStrings.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/connector/LocalStrings.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/connector/LocalStrings.properties
@@ -45,6 +45,7 @@ coyoteRequest.attributeEvent=Exception t
 coyoteRequest.authenticate.ise=Cannot call authenticate() after the response has been committed
 coyoteRequest.changeSessionId=Cannot change session ID. There is no session associated with this request.
 coyoteRequest.chunkedPostTooLarge=Parameters were not parsed because the size of the posted data was too big. Because this request was a chunked request, it could not be processed further. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
+coyoteRequest.deletePartFailed=Failed to deleted temporary file used for part [{0}]
 coyoteRequest.filterAsyncSupportUnknown=Unable to determine if any filters do not support async processing
 coyoteRequest.getContextPath.ise=Unable to find match between the canonical context path [{0}] and the URI presented by the user agent [{1}]
 coyoteRequest.getInputStream.ise=getReader() has already been called for this request
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/connector/Request.java
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/connector/Request.java
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/connector/Request.java
@@ -473,8 +473,9 @@ public class Request implements HttpServ
             for (Part part: parts) {
                 try {
                     part.delete();
-                } catch (IOException ignored) {
-                    // ApplicationPart.delete() never throws an IOEx
+                } catch (Throwable t) {
+                    ExceptionUtils.handleThrowable(t);
+                    log.warn(sm.getString("coyoteRequest.deletePartFailed", part.getName()), t);
                 }
             }
             parts = null;
@@ -526,8 +527,8 @@ public class Request implements HttpServ
         asyncSupported = null;
         if (asyncContext!=null) {
             asyncContext.recycle();
+            asyncContext = null;
         }
-        asyncContext = null;
     }
 
 
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/ApplicationHttpRequest.java
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/ApplicationHttpRequest.java
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/ApplicationHttpRequest.java
@@ -50,6 +50,7 @@ import org.apache.catalina.connector.Req
 import org.apache.catalina.util.ParameterMap;
 import org.apache.catalina.util.RequestUtil;
 import org.apache.catalina.util.URLEncoder;
+import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.http.Parameters;
@@ -645,7 +646,12 @@ class ApplicationHttpRequest extends Htt
      */
     public void recycle() {
         if (session != null) {
-            session.endAccess();
+            try {
+                session.endAccess();
+            } catch (Throwable t) {
+                ExceptionUtils.handleThrowable(t);
+                context.getLogger().warn(sm.getString("applicationHttpRequest.sessionEndAccessFail"), t);
+            }
         }
     }
 
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings.properties
@@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitPa
 applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}]
 
 applicationHttpRequest.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed
+applicationHttpRequest.sessionEndAccessFail=Exception triggered ending access to session while recycling request
 
 applicationPushBuilder.methodInvalid=The HTTP method for a push request must be both cacheable and safe but [{0}] is not
 applicationPushBuilder.methodNotToken=HTTP methods must be tokens but [{0}] contains a non-token character
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_cs.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings_cs.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_cs.properties
@@ -24,6 +24,8 @@ applicationDispatcher.specViolation.resp
 
 applicationFilterRegistration.nullInitParams=Není možné nastavit inicializační parametry pro filtr kvůli hodnotě null ve jménu či hodnotě. Jméno [{0}], Hodnota [{1}]
 
+applicationHttpRequest.sessionEndAccessFail=Výjimka vyvolala ukončení přístupu k session během recykllování dotazu
+
 aprListener.initializingFIPS=Inicializace FIPS módu...
 
 containerBase.backgroundProcess.cluster=Výjimka při zpracování procesu na pozadí v clusteru [{0}]
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_es.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings_es.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_es.properties
@@ -50,6 +50,8 @@ applicationFilterConfig.jmxUnregisterFai
 applicationFilterRegistration.nullInitParam=No puedo poner el parámetro de inicialización para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}]
 applicationFilterRegistration.nullInitParams=No puedo poner los parámetros de inicialización para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}]
 
+applicationHttpRequest.sessionEndAccessFail=Excepción disparada acabando acceso a sesión mientras se reciclaba el requerimiento
+
 applicationServletRegistration.setServletSecurity.iae=Se ha especificado restricción Null para el servlet [{0}] desplegado en el contexto con el nombre [{1}]
 applicationServletRegistration.setServletSecurity.ise=No se pueden añadir restricciones de seguridad al servlet [{0}] desplegado en el contexto con el nombre [{1}] ya que el contexto ya ha sido inicializado.
 
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_fr.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings_fr.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_fr.properties
@@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitPa
 applicationFilterRegistration.nullInitParams=Impossible de fixer les paramètres d''initialisation du filtre, à cause d''un nom ou d''une valeur nulle, nom [{0}], valeur [{1}]
 
 applicationHttpRequest.fragmentInDispatchPath=Le fragment dans le chemin de dispatch [{0}] a été enlevé
+applicationHttpRequest.sessionEndAccessFail=Exception lancée durant l'arrêt de l'accès à la session durant le recyclage de la requête
 
 applicationPushBuilder.methodInvalid=La méthode HTTP pour une requête push doit être à la fois être sans danger et pouvoir être mise en cache, mais [{0}] ne correspond pas
 applicationPushBuilder.methodNotToken=Les méthodes HTTP doivent être des "token", mais [{0}] contient un caractère invalide dans un token.
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_ja.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings_ja.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_ja.properties
@@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitPa
 applicationFilterRegistration.nullInitParams=キー [{0}] または値 [{1}] のいずれかが null のためフィルターの初期化パラメータを設定できませんでした。
 
 applicationHttpRequest.fragmentInDispatchPath=ディスパッチパス [{0}] 中のフラグメントは除去されました
+applicationHttpRequest.sessionEndAccessFail=リクエストの再利用中に行ったセッションへのアクセス終了処理で例外が送出されました。
 
 applicationPushBuilder.methodInvalid=プッシュリクエストの HTTP メソッドはキャッシュ可能、かつ、安全でなければなりません。[{0}] は指定できません。
 applicationPushBuilder.methodNotToken=HTTP メソッド [{0}] にトークンとして利用できない文字が含まれています。
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_ko.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings_ko.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_ko.properties
@@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitPa
 applicationFilterRegistration.nullInitParams=널인 이름 또는 값 때문에, 필터의 초기화 파라미터를 설정할 수 없습니다. 이름: [{0}], 값: [{1}]
 
 applicationHttpRequest.fragmentInDispatchPath=디스패치 경로 [{0}](으)로부터 URI fragment를 제거했습니다.
+applicationHttpRequest.sessionEndAccessFail=요청을 참조 해제하는 과정에서, 세션에 대한 접근을 종료시키려 개시하는 중 예외 발생
 
 applicationPushBuilder.methodInvalid=PUSH 요청을 위한 HTTP 메소드는 반드시 캐시 가능하고 안전해야 하는데, [{0}]은(는) 그렇지 않습니다.
 applicationPushBuilder.methodNotToken=HTTP 메소드들은 토큰들이어야 하지만, [{0}]은(는) 토큰이 아닌 문자를 포함하고 있습니다.
Index: apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_zh_CN.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/catalina/core/LocalStrings_zh_CN.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/catalina/core/LocalStrings_zh_CN.properties
@@ -60,6 +60,7 @@ applicationFilterRegistration.nullInitPa
 applicationFilterRegistration.nullInitParams=由于name和(或)value为null，无法为过滤器设置初始化参数。name为 [{0}]，value为 [{1}]
 
 applicationHttpRequest.fragmentInDispatchPath=调度路径[{0}]中的片段已被删除
+applicationHttpRequest.sessionEndAccessFail=在回收请求时，异常触发了对会话的结束访问。
 
 applicationPushBuilder.methodInvalid=推送请求的HTTP方法必须既可缓存又安全，但是[{0}]不是
 applicationPushBuilder.methodNotToken=HTTP方法必须是令牌(token)，但 [{0}] 包含非令牌字符
Index: apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/buf/B2CConverter.java
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/tomcat/util/buf/B2CConverter.java
+++ apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/buf/B2CConverter.java
@@ -28,6 +28,9 @@ import java.nio.charset.CodingErrorActio
 import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -35,6 +38,7 @@ import org.apache.tomcat.util.res.String
  */
 public class B2CConverter {
 
+    private static final Log log = LogFactory.getLog(B2CConverter.class);
     private static final StringManager sm = StringManager.getManager(B2CConverter.class);
 
     private static final CharsetCache charsetCache = new CharsetCache();
@@ -107,7 +111,12 @@ public class B2CConverter {
      * Reset the decoder state.
      */
     public void recycle() {
-        decoder.reset();
+        try {
+            decoder.reset();
+        } catch (Throwable t) {
+            ExceptionUtils.handleThrowable(t);
+            log.warn(sm.getString("b2cConverter.decoderResetFail", decoder.charset()), t);
+        }
         ((Buffer)leftovers).position(0);
     }
 
Index: apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/buf/C2BConverter.java
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/tomcat/util/buf/C2BConverter.java
+++ apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/buf/C2BConverter.java
@@ -25,11 +25,19 @@ import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
 
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
+import org.apache.tomcat.util.res.StringManager;
+
 /**
  * NIO based character encoder.
  */
 public final class C2BConverter {
 
+    private static final Log log = LogFactory.getLog(C2BConverter.class);
+    private static final StringManager sm = StringManager.getManager(C2BConverter.class);
+
     private final CharsetEncoder encoder;
     private ByteBuffer bb = null;
     private CharBuffer cb = null;
@@ -51,7 +59,12 @@ public final class C2BConverter {
      * Reset the encoder state.
      */
     public void recycle() {
-        encoder.reset();
+        try {
+            encoder.reset();
+        } catch (Throwable t) {
+            ExceptionUtils.handleThrowable(t);
+            log.warn(sm.getString("c2bConverter.decoderResetFail", encoder.charset()), t);
+        }
         ((Buffer)leftovers).position(0);
     }
 
Index: apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/buf/LocalStrings.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/tomcat/util/buf/LocalStrings.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/buf/LocalStrings.properties
@@ -16,10 +16,13 @@
 asn1Parser.lengthInvalid=Invalid length [{0}] bytes reported when the input data length is [{1}] bytes
 asn1Parser.tagMismatch=Expected to find value [{0}] but found value [{1}]
 
+b2cConverter.decoderResetFail=Failed to reset instance of decoder for character set [{0}]
 b2cConverter.unknownEncoding=The character encoding [{0}] is not supported
 
 byteBufferUtils.cleaner=Cannot use direct ByteBuffer cleaner, memory leaking may occur
 
+c2bConverter.encoderResetFail=Failed to reset instance of encoder for character set [{0}]
+
 chunk.overflow=Buffer overflow and no sink is set, limit [{0}] and buffer length [{1}]
 
 encodedSolidusHandling.invalid=The value [{0}] is not recognised
Index: apache-tomcat-9.0.36-src/webapps/docs/changelog.xml
===================================================================
--- apache-tomcat-9.0.36-src.orig/webapps/docs/changelog.xml
+++ apache-tomcat-9.0.36-src/webapps/docs/changelog.xml
@@ -111,6 +111,10 @@
       <fix>
         Avoid protocol relative redirects in FORM authentication. (markt)
       </fix>
+      <add>
+        Improve handling of failures within <code>recycle()</code> methods.
+        (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Coyote">
