-
+diff --git a/java/org/apache/catalina/util/ServerInfo.properties b/java/org/apache/catalina/util/ServerInfo.properties
+index 3aa34f4..c8dff06 100644
--- a/java/org/apache/catalina/util/ServerInfo.properties
+++ b/java/org/apache/catalina/util/ServerInfo.properties
@@ -13,7 +13,7 @@
diff -Nru tomcat10-10.1.40/debian/patches/0021-dont-test-unsupported-ciphers.patch tomcat10-10.1.52/debian/patches/0021-dont-test-unsupported-ciphers.patch
--- tomcat10-10.1.40/debian/patches/0021-dont-test-unsupported-ciphers.patch 2025-04-03 13:28:21.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/0021-dont-test-unsupported-ciphers.patch 2026-02-03 12:29:34.000000000 +0000
@@ -12,9 +12,11 @@
.../tomcat/util/net/openssl/ciphers/TesterOpenSSL.java | 18 ++++++++++++++++++
3 files changed, 20 insertions(+), 2 deletions(-)
+diff --git a/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java b/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
+index 9b9eb5e..9d81307 100644
--- a/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
+++ b/test/org/apache/tomcat/util/net/openssl/ciphers/TestCipher.java
-@@ -76,7 +76,7 @@
+@@ -76,7 +76,7 @@ public class TestCipher {
// OpenSSL does not include ECDH/ECDHE ciphers in all and there is no
// EC alias. Use aRSA.
// OpenSSL 1.0.0 onwards does not include eNULL in all.
@@ -23,9 +25,11 @@
Set expectedCipherSuites = new HashSet<>();
for (Cipher cipher : Cipher.values()) {
+diff --git a/test/org/apache/tomcat/util/net/openssl/ciphers/TestOpenSSLCipherConfigurationParser.java b/test/org/apache/tomcat/util/net/openssl/ciphers/TestOpenSSLCipherConfigurationParser.java
+index 1c2b946..8bb4315 100644
--- a/test/org/apache/tomcat/util/net/openssl/ciphers/TestOpenSSLCipherConfigurationParser.java
+++ b/test/org/apache/tomcat/util/net/openssl/ciphers/TestOpenSSLCipherConfigurationParser.java
-@@ -573,7 +573,7 @@
+@@ -573,7 +573,7 @@ public class TestOpenSSLCipherConfigurationParser {
private void testSpecification(String specification) throws Exception {
// Filter out cipher suites that OpenSSL does not implement
@@ -34,9 +38,11 @@
List jsseCipherListFromOpenSSL =
OpenSSLCipherConfigurationParser.parseExpression(openSSLCipherList);
List jsseCipherListFromParser =
+diff --git a/test/org/apache/tomcat/util/net/openssl/ciphers/TesterOpenSSL.java b/test/org/apache/tomcat/util/net/openssl/ciphers/TesterOpenSSL.java
+index 1c1cf5a..0dc9db8 100644
--- a/test/org/apache/tomcat/util/net/openssl/ciphers/TesterOpenSSL.java
+++ b/test/org/apache/tomcat/util/net/openssl/ciphers/TesterOpenSSL.java
-@@ -105,6 +105,24 @@
+@@ -105,6 +105,24 @@ public class TesterOpenSSL {
unimplemented.add(Cipher.SSL2_RC4_128_EXPORT40_WITH_MD5);
unimplemented.add(Cipher.SSL2_IDEA_128_CBC_WITH_MD5);
unimplemented.add(Cipher.SSL2_DES_192_EDE3_CBC_WITH_MD5);
diff -Nru tomcat10-10.1.40/debian/patches/0023-disable-shutdown-by-socket.patch tomcat10-10.1.52/debian/patches/0023-disable-shutdown-by-socket.patch
--- tomcat10-10.1.40/debian/patches/0023-disable-shutdown-by-socket.patch 2025-04-03 13:25:26.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/0023-disable-shutdown-by-socket.patch 2026-02-03 12:29:34.000000000 +0000
@@ -7,6 +7,8 @@
conf/server.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
+diff --git a/conf/server.xml b/conf/server.xml
+index 0ab6264..cf8f617 100644
--- a/conf/server.xml
+++ b/conf/server.xml
@@ -19,7 +19,7 @@
diff -Nru tomcat10-10.1.40/debian/patches/0024-systemd-log-formatter.patch tomcat10-10.1.52/debian/patches/0024-systemd-log-formatter.patch
--- tomcat10-10.1.40/debian/patches/0024-systemd-log-formatter.patch 2025-04-03 13:25:26.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/0024-systemd-log-formatter.patch 2026-02-03 12:29:34.000000000 +0000
@@ -8,6 +8,9 @@
1 file changed, 109 insertions(+)
create mode 100644 java/org/apache/juli/SystemdFormatter.java
+diff --git a/java/org/apache/juli/SystemdFormatter.java b/java/org/apache/juli/SystemdFormatter.java
+new file mode 100644
+index 0000000..014a193
--- /dev/null
+++ b/java/org/apache/juli/SystemdFormatter.java
@@ -0,0 +1,109 @@
diff -Nru tomcat10-10.1.40/debian/patches/0025-invalid-configuration-exit-status.patch tomcat10-10.1.52/debian/patches/0025-invalid-configuration-exit-status.patch
--- tomcat10-10.1.40/debian/patches/0025-invalid-configuration-exit-status.patch 2025-04-03 13:28:17.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/0025-invalid-configuration-exit-status.patch 2026-02-03 12:29:34.000000000 +0000
@@ -8,9 +8,11 @@
java/org/apache/catalina/startup/Bootstrap.java | 4 ++++
1 file changed, 4 insertions(+)
+diff --git a/java/org/apache/catalina/startup/Bootstrap.java b/java/org/apache/catalina/startup/Bootstrap.java
+index 8dfc1fb..7250ff7 100644
--- a/java/org/apache/catalina/startup/Bootstrap.java
+++ b/java/org/apache/catalina/startup/Bootstrap.java
-@@ -473,6 +473,10 @@
+@@ -470,6 +470,10 @@ public final class Bootstrap {
case "start":
daemon.setAwait(true);
daemon.load(args);
diff -Nru tomcat10-10.1.40/debian/patches/0026-easymock4-compatibility.patch tomcat10-10.1.52/debian/patches/0026-easymock4-compatibility.patch
--- tomcat10-10.1.40/debian/patches/0026-easymock4-compatibility.patch 2025-04-03 13:25:26.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/0026-easymock4-compatibility.patch 2026-02-03 12:29:34.000000000 +0000
@@ -5,12 +5,13 @@
Forwarded: no
---
.../valves/TestCrawlerSessionManagerValve.java | 28 +++++++++++-----------
- test/org/apache/catalina/valves/TestSSLValve.java | 4 ++--
- 2 files changed, 16 insertions(+), 16 deletions(-)
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+diff --git a/test/org/apache/catalina/valves/TestCrawlerSessionManagerValve.java b/test/org/apache/catalina/valves/TestCrawlerSessionManagerValve.java
+index c813156..484ebf8 100644
--- a/test/org/apache/catalina/valves/TestCrawlerSessionManagerValve.java
+++ b/test/org/apache/catalina/valves/TestCrawlerSessionManagerValve.java
-@@ -57,13 +57,13 @@ public class TestCrawlerSessionManagerVa
+@@ -57,13 +57,13 @@ public class TestCrawlerSessionManagerValve {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerIps("216\\.58\\.206\\.174");
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
@@ -26,7 +27,7 @@
EasyMock.verify(request, session);
}
-@@ -73,13 +73,13 @@ public class TestCrawlerSessionManagerVa
+@@ -73,13 +73,13 @@ public class TestCrawlerSessionManagerValve {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerIps("216\\.58\\.206\\.174");
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
@@ -42,7 +43,7 @@
EasyMock.verify(request, session);
}
-@@ -90,7 +90,7 @@ public class TestCrawlerSessionManagerVa
+@@ -90,7 +90,7 @@ public class TestCrawlerSessionManagerValve {
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setHostAware(true);
valve.setContextAware(true);
@@ -51,7 +52,7 @@
verifyCrawlingLocalhost(valve, "localhost");
verifyCrawlingLocalhost(valve, "example.invalid");
-@@ -102,7 +102,7 @@ public class TestCrawlerSessionManagerVa
+@@ -102,7 +102,7 @@ public class TestCrawlerSessionManagerValve {
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setHostAware(true);
valve.setContextAware(true);
@@ -60,7 +61,7 @@
verifyCrawlingContext(valve, "/examples");
verifyCrawlingContext(valve, null);
-@@ -113,7 +113,7 @@ public class TestCrawlerSessionManagerVa
+@@ -113,7 +113,7 @@ public class TestCrawlerSessionManagerValve {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerIps("216\\.58\\.206\\.174");
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
@@ -69,7 +70,7 @@
valve.setSessionInactiveInterval(0);
StandardSession session = new StandardSession(TEST_MANAGER);
session.setId("id");
-@@ -123,7 +123,7 @@ public class TestCrawlerSessionManagerVa
+@@ -123,7 +123,7 @@ public class TestCrawlerSessionManagerValve {
EasyMock.replay(request);
@@ -78,7 +79,7 @@
EasyMock.verify(request);
-@@ -142,7 +142,7 @@ public class TestCrawlerSessionManagerVa
+@@ -142,7 +142,7 @@ public class TestCrawlerSessionManagerValve {
EasyMock.replay(request, session);
@@ -87,7 +88,7 @@
EasyMock.verify(request, session);
}
-@@ -156,14 +156,14 @@ public class TestCrawlerSessionManagerVa
+@@ -156,14 +156,14 @@ public class TestCrawlerSessionManagerValve {
EasyMock.replay(request, session);
@@ -104,16 +105,16 @@
if (isBot) {
EasyMock.expect(session.getId()).andReturn("id").times(1);
session.setAttribute(EasyMock.eq(valve.getClass().getName()),
-@@ -182,7 +182,7 @@ public class TestCrawlerSessionManagerVa
+@@ -182,7 +182,7 @@ public class TestCrawlerSessionManagerValve {
private Request createRequestExpectations(String ip, HttpSession session, boolean isBot, String hostname,
String contextPath, String userAgent) {
- Request request = EasyMock.createMock(Request.class);
+ Request request = (Request) EasyMock.createMock(Request.class);
EasyMock.expect(request.getRemoteAddr()).andReturn(ip);
+ EasyMock.expect(request.getRemoteAddr()).andReturn(ip);
EasyMock.expect(request.getHost()).andReturn(simpleHostWithName(hostname));
- EasyMock.expect(request.getContext()).andReturn(simpleContextWithName(contextPath));
-@@ -196,7 +196,7 @@ public class TestCrawlerSessionManagerVa
+@@ -198,7 +198,7 @@ public class TestCrawlerSessionManagerValve {
}
private Host simpleHostWithName(String hostname) {
@@ -122,7 +123,7 @@
EasyMock.expect(host.getName()).andReturn(hostname);
EasyMock.replay(host);
return host;
-@@ -206,7 +206,7 @@ public class TestCrawlerSessionManagerVa
+@@ -208,7 +208,7 @@ public class TestCrawlerSessionManagerValve {
if (contextPath == null) {
return null;
}
@@ -131,23 +132,3 @@
EasyMock.expect(context.getName()).andReturn(contextPath);
EasyMock.replay(context);
return context;
---- a/test/org/apache/catalina/valves/TestSSLValve.java
-+++ b/test/org/apache/catalina/valves/TestSSLValve.java
-@@ -37,7 +37,7 @@ public class TestSSLValve {
- public static class MockRequest extends Request {
-
- public MockRequest() {
-- super(EasyMock.createMock(Connector.class));
-+ super((Connector) EasyMock.createMock(Connector.class));
- setCoyoteRequest(new org.apache.coyote.Request());
- }
-
-@@ -94,7 +94,7 @@ public class TestSSLValve {
- private SSLValve valve = new SSLValve();
-
- private MockRequest mockRequest = new MockRequest();
-- private Valve mockNext = EasyMock.createMock(Valve.class);
-+ private Valve mockNext = (Valve) EasyMock.createMock(Valve.class);
-
-
- @Before
diff -Nru tomcat10-10.1.40/debian/patches/0030-eclipse-jdt-classpath.patch tomcat10-10.1.52/debian/patches/0030-eclipse-jdt-classpath.patch
--- tomcat10-10.1.40/debian/patches/0030-eclipse-jdt-classpath.patch 2025-04-03 13:25:26.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/0030-eclipse-jdt-classpath.patch 2026-02-03 12:29:34.000000000 +0000
@@ -1,6 +1,14 @@
-Description: Updates the Eclipse Compiler classpath
-Author: Emmanuel Bourg
+From: Emmanuel Bourg
+Date: Wed, 28 Jan 2026 04:57:59 +0100
+Subject: Updates the Eclipse Compiler classpath
+
Forwarded: no
+---
+ build.xml | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/build.xml b/build.xml
+index 5f30263..7d05c45 100644
--- a/build.xml
+++ b/build.xml
@@ -233,6 +233,7 @@
diff -Nru tomcat10-10.1.40/debian/patches/disable-jacoco.patch tomcat10-10.1.52/debian/patches/disable-jacoco.patch
--- tomcat10-10.1.40/debian/patches/disable-jacoco.patch 2025-04-03 13:28:24.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/disable-jacoco.patch 2026-02-03 12:29:34.000000000 +0000
@@ -1,15 +1,17 @@
From: Markus Koschany
-Date: Wed, 1 Feb 2023 00:11:33 +0100
-Subject: disable-jacoco
+Date: Wed, 28 Jan 2026 04:59:30 +0100
+Subject: disable jacoco
Forwarded: not-needed
---
build.xml | 12 ------------
1 file changed, 12 deletions(-)
+diff --git a/build.xml b/build.xml
+index 7d05c45..969b037 100644
--- a/build.xml
+++ b/build.xml
-@@ -2054,10 +2054,6 @@
+@@ -2167,10 +2167,6 @@
@@ -17,10 +19,10 @@
- enabled="${test.coverage}"
- destfile="${coverage.datafile}"
- >
-
@@ -28,7 +30,7 @@
-@@ -3723,15 +3718,8 @@
+@@ -3853,15 +3848,8 @@ Configured for ${release.asfusername} to release Tomcat ${version.major}.${versi
diff -Nru tomcat10-10.1.40/debian/patches/exclude-TestJNDIRealmIntegration.patch tomcat10-10.1.52/debian/patches/exclude-TestJNDIRealmIntegration.patch
--- tomcat10-10.1.40/debian/patches/exclude-TestJNDIRealmIntegration.patch 2025-04-03 13:28:22.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/exclude-TestJNDIRealmIntegration.patch 2026-02-03 12:29:34.000000000 +0000
@@ -1,5 +1,5 @@
From: Markus Koschany
-Date: Fri, 24 Sep 2021 16:29:54 +0200
+Date: Wed, 28 Jan 2026 05:12:44 +0100
Subject: exclude TestJNDIRealmIntegration
Exclude TestJNDIRealmIntegration.java because it FTBFS due to missing
@@ -7,20 +7,22 @@
Forwarded: not-needed
---
- build.xml | 1 +
- 1 file changed, 1 insertion(+)
+ build.xml | 2 ++
+ 1 file changed, 2 insertions(+)
+diff --git a/build.xml b/build.xml
+index 969b037..5c56c29 100644
--- a/build.xml
+++ b/build.xml
-@@ -1929,6 +1929,7 @@
+@@ -1945,6 +1945,7 @@
-
+
+
-@@ -2125,6 +2126,7 @@
+@@ -2235,6 +2236,7 @@
tests. See below for more details.
-->
diff -Nru tomcat10-10.1.40/debian/patches/series tomcat10-10.1.52/debian/patches/series
--- tomcat10-10.1.40/debian/patches/series 2025-04-03 13:25:26.000000000 +0000
+++ tomcat10-10.1.52/debian/patches/series 2026-02-03 12:29:34.000000000 +0000
@@ -10,6 +10,6 @@
0025-invalid-configuration-exit-status.patch
0026-easymock4-compatibility.patch
0021-dont-test-unsupported-ciphers.patch
-exclude-TestJNDIRealmIntegration.patch
-disable-jacoco.patch
0030-eclipse-jdt-classpath.patch
+disable-jacoco.patch
+exclude-TestJNDIRealmIntegration.patch
diff -Nru tomcat10-10.1.40/java/jakarta/el/ELContextListener.java tomcat10-10.1.52/java/jakarta/el/ELContextListener.java
--- tomcat10-10.1.40/java/jakarta/el/ELContextListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/el/ELContextListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -16,9 +16,6 @@
*/
package jakarta.el;
-/**
- * @author Jacob Hookom [jacob/hookom.net]
- */
public interface ELContextListener extends java.util.EventListener {
void contextCreated(ELContextEvent event);
diff -Nru tomcat10-10.1.40/java/jakarta/el/ELResolver.java tomcat10-10.1.52/java/jakarta/el/ELResolver.java
--- tomcat10-10.1.40/java/jakarta/el/ELResolver.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/el/ELResolver.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,9 +18,6 @@
import java.util.Iterator;
-/**
- * @author Jacob Hookom [jacob/hookom.net]
- */
public abstract class ELResolver {
public static final String TYPE = "type";
diff -Nru tomcat10-10.1.40/java/jakarta/el/ExpressionFactory.java tomcat10-10.1.52/java/jakarta/el/ExpressionFactory.java
--- tomcat10-10.1.40/java/jakarta/el/ExpressionFactory.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/el/ExpressionFactory.java 2026-01-23 19:33:36.000000000 +0000
@@ -360,8 +360,8 @@
}
} catch (FileNotFoundException e) {
// Should not happen - ignore it if it does
- } catch (IOException e) {
- throw new ELException(Util.message(null, "expressionFactory.readFailed", PROPERTY_FILE), e);
+ } catch (IOException ioe) {
+ throw new ELException(Util.message(null, "expressionFactory.readFailed", PROPERTY_FILE), ioe);
}
}
return null;
@@ -375,4 +375,4 @@
return null;
}
-}
+}
\ No newline at end of file
diff -Nru tomcat10-10.1.40/java/jakarta/el/ImportHandler.java tomcat10-10.1.52/java/jakarta/el/ImportHandler.java
--- tomcat10-10.1.40/java/jakarta/el/ImportHandler.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/el/ImportHandler.java 2026-01-23 19:33:36.000000000 +0000
@@ -136,7 +136,7 @@
standardPackages.put("jakarta.servlet.jsp", servletJspClassNames);
Set javaLangClassNames = new HashSet<>();
- // Based on Java 21 EA29
+ // Based on Java 26 EA26
// Interfaces
javaLangClassNames.add("Appendable");
javaLangClassNames.add("AutoCloseable");
@@ -144,6 +144,7 @@
javaLangClassNames.add("Cloneable");
javaLangClassNames.add("Comparable");
javaLangClassNames.add("Iterable");
+ javaLangClassNames.add("LazyConstant");
javaLangClassNames.add("ProcessHandle");
javaLangClassNames.add("ProcessHandle.Info");
javaLangClassNames.add("Readable");
@@ -168,6 +169,7 @@
javaLangClassNames.add("Enum");
javaLangClassNames.add("Enum.EnumDesc");
javaLangClassNames.add("Float");
+ javaLangClassNames.add("IO");
javaLangClassNames.add("InheritableThreadLocal");
javaLangClassNames.add("Integer");
javaLangClassNames.add("Long");
@@ -190,6 +192,7 @@
javaLangClassNames.add("ScopedValue.Carrier");
javaLangClassNames.add("SecurityManager");
javaLangClassNames.add("Short");
+ javaLangClassNames.add("StableValue");
javaLangClassNames.add("StackTraceElement");
javaLangClassNames.add("StackWalker");
javaLangClassNames.add("StrictMath");
@@ -400,6 +403,18 @@
clazzes.put(name, clazz);
return clazz;
}
+ // Might be an inner class
+ StringBuilder sb = new StringBuilder(className);
+ int replacementPosition = sb.lastIndexOf(".");
+ while (replacementPosition > -1) {
+ sb.setCharAt(replacementPosition, '$');
+ clazz = findClass(sb.toString(), true);
+ if (clazz != null) {
+ clazzes.put(name, clazz);
+ return clazz;
+ }
+ replacementPosition = sb.lastIndexOf(".", replacementPosition);
+ }
}
// Search the package imports - note there may be multiple matches
diff -Nru tomcat10-10.1.40/java/jakarta/el/Util.java tomcat10-10.1.52/java/jakarta/el/Util.java
--- tomcat10-10.1.40/java/jakarta/el/Util.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/el/Util.java 2026-01-23 19:33:36.000000000 +0000
@@ -130,7 +130,7 @@
try {
Method method = clazz.getMethod(methodName, paramTypes);
return getMethod(clazz, base, method);
- } catch (NoSuchMethodException | SecurityException e) {
+ } catch (NoSuchMethodException | SecurityException ignore) {
// Fall through to broader, slower logic
}
}
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/LocalStrings_ru.properties tomcat10-10.1.52/java/jakarta/servlet/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/jakarta/servlet/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -17,3 +17,9 @@
# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
httpMethodConstraintElement.invalidMethod=Ошибочный HTTP метод
+
+value.false=ложный
+value.true=истина
+
+wrapper.nullRequest=запрос не может быть null
+wrapper.nullResponse=Ответ не может быть null
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/http/HttpServlet.java tomcat10-10.1.52/java/jakarta/servlet/http/HttpServlet.java
--- tomcat10-10.1.40/java/jakarta/servlet/http/HttpServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/http/HttpServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -683,9 +683,8 @@
if (REQUEST_FACADE_CLAZZ.isAssignableFrom(req.getClass())) {
try {
return ((Boolean) GET_ALLOW_TRACE.invoke(req, (Object[]) null)).booleanValue();
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ignore) {
// Should never happen given the checks in place.
- // Ignore
}
}
}
@@ -892,11 +891,11 @@
Writer osw = null;
try {
osw = new OutputStreamWriter(out, encoding);
- } catch (UnsupportedEncodingException e) {
- // Impossible.
- // The same values were used in the constructor. If this method
- // gets called then the constructor must have succeeded so the
- // above call must also succeed.
+ } catch (UnsupportedEncodingException ignore) {
+ /*
+ * Impossible. The same values were used in the constructor. If this method gets called then the
+ * constructor must have succeeded so the above call must also succeed.
+ */
}
pw = new PrintWriter(osw);
}
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/http/HttpServletRequest.java tomcat10-10.1.52/java/jakarta/servlet/http/HttpServletRequest.java
--- tomcat10-10.1.40/java/jakarta/servlet/http/HttpServletRequest.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/http/HttpServletRequest.java 2026-01-23 19:33:36.000000000 +0000
@@ -294,8 +294,8 @@
String getRequestedSessionId();
/**
- * Returns the part of this request's URL from the protocol name up to the query string in the first line of the
- * HTTP request. The web container does not decode this String. For example:
+ * Returns the URI path part of this request's URL which starts after the authority (if any) and ends before the
+ * query string delimiter ({@code ?}), if any. The web container does not decode this String. For example:
*
*
Examples of Returned Values
*
@@ -317,7 +317,8 @@
*
* To reconstruct a URL with a scheme and host, use {@link #getRequestURL}.
*
- * @return a String containing the part of the URL from the protocol name up to the query string
+ * @return a String containing the path part of the URL from after the authority to before the query
+ * string
*
* @see #getRequestURL
*/
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/http/LocalStrings_ja.properties tomcat10-10.1.52/java/jakarta/servlet/http/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/jakarta/servlet/http/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/http/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -28,7 +28,7 @@
http.method_delete_not_supported=HTTPのDELETEメソッドは、このURLではサポートされていません。
http.method_get_not_supported=HTTPのGETメソッドは、このURLではサポートされていません。
-http.method_not_implemented=メソッド [{0}] は RFC 2068 には定義されておらず、サーブレット API ではサポートされません
+http.method_not_implemented=メソッド [{0}] はこの URI のこのサーブレットでは実装されていません
http.method_post_not_supported=HTTPのPOSTメソッドは、このURLではサポートされていません。
http.method_put_not_supported=HTTPのPUTメソッドは、このURLではサポートされていません。
http.non_http=リクエストが HTTP リクエストではない、あるいはレスポンスが HTTP レスポンスではありません。
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/http/LocalStrings_ru.properties tomcat10-10.1.52/java/jakarta/servlet/http/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/jakarta/servlet/http/LocalStrings_ru.properties 1970-01-01 00:00:00.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/http/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -0,0 +1,21 @@
+# 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.
+
+# Do not edit this file directly.
+# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
+
+http.method_get_not_supported=HTTP метод GET не поддерживается этим URL
+http.method_post_not_supported=HTTP метод POST не поддерживается этим URL
+http.method_put_not_supported=HTTP метод PUT не поддерживается этим URL
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/jsp/LocalStrings_ru.properties tomcat10-10.1.52/java/jakarta/servlet/jsp/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/jakarta/servlet/jsp/LocalStrings_ru.properties 1970-01-01 00:00:00.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/jsp/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -0,0 +1,19 @@
+# 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.
+
+# Do not edit this file directly.
+# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
+
+el.unknown.identifier=Неизвестный идентификатор
diff -Nru tomcat10-10.1.40/java/jakarta/servlet/jsp/tagext/BodyContent.java tomcat10-10.1.52/java/jakarta/servlet/jsp/tagext/BodyContent.java
--- tomcat10-10.1.40/java/jakarta/servlet/jsp/tagext/BodyContent.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/servlet/jsp/tagext/BodyContent.java 2026-01-23 19:33:36.000000000 +0000
@@ -71,7 +71,7 @@
public void clearBody() {
try {
this.clear();
- } catch (IOException ex) {
+ } catch (IOException ioe) {
// TODO -- clean this one up.
throw new Error("internal error!;");
}
diff -Nru tomcat10-10.1.40/java/jakarta/websocket/ContainerProvider.java tomcat10-10.1.52/java/jakarta/websocket/ContainerProvider.java
--- tomcat10-10.1.40/java/jakarta/websocket/ContainerProvider.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/websocket/ContainerProvider.java 2026-01-23 19:33:36.000000000 +0000
@@ -47,7 +47,7 @@
Class clazz =
(Class) Class.forName(DEFAULT_PROVIDER_CLASS_NAME);
result = clazz.getConstructor().newInstance();
- } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+ } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException ignore) {
// No options left. Just return null.
}
}
diff -Nru tomcat10-10.1.40/java/jakarta/websocket/server/ServerEndpointConfig.java tomcat10-10.1.52/java/jakarta/websocket/server/ServerEndpointConfig.java
--- tomcat10-10.1.40/java/jakarta/websocket/server/ServerEndpointConfig.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/jakarta/websocket/server/ServerEndpointConfig.java 2026-01-23 19:33:36.000000000 +0000
@@ -182,7 +182,7 @@
@SuppressWarnings("unchecked")
Class clazz = (Class) Class.forName(DEFAULT_IMPL_CLASSNAME);
result = clazz.getConstructor().newInstance();
- } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+ } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException ignore) {
// No options left. Just return null.
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Authenticator.java tomcat10-10.1.52/java/org/apache/catalina/Authenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/Authenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Authenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -27,8 +27,6 @@
/**
* An Authenticator is a component (usually a Valve or Container) that provides some sort of authentication
* service.
- *
- * @author Craig R. McClanahan
*/
public interface Authenticator {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Cluster.java tomcat10-10.1.52/java/org/apache/catalina/Cluster.java
--- tomcat10-10.1.40/java/org/apache/catalina/Cluster.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Cluster.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,9 +21,6 @@
* support different ways to communicate within the Cluster. A Cluster implementation is responsible for setting up a
* way to communicate within the Cluster and also supply "ClientApplications" with ClusterSender used when
* sending information in the Cluster and ClusterInfo used for receiving information in the Cluster.
- *
- * @author Bip Thelin
- * @author Remy Maucherat
*/
public interface Cluster extends Contained {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Contained.java tomcat10-10.1.52/java/org/apache/catalina/Contained.java
--- tomcat10-10.1.40/java/org/apache/catalina/Contained.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Contained.java 2026-01-23 19:33:36.000000000 +0000
@@ -17,13 +17,8 @@
package org.apache.catalina;
/**
- *
* Decoupling interface which specifies that an implementing class is associated with at most one
* Container instance.
- *
- *
- * @author Craig R. McClanahan
- * @author Peter Donald
*/
public interface Contained {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Container.java tomcat10-10.1.52/java/org/apache/catalina/Container.java
--- tomcat10-10.1.40/java/org/apache/catalina/Container.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Container.java 2026-01-23 19:33:36.000000000 +0000
@@ -60,9 +60,6 @@
*
Resources - JNDI directory context enabling access to static resources, enabling custom linkages to
* existing server components when Catalina is embedded in a larger server.
*
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public interface Container extends Lifecycle {
@@ -429,7 +426,7 @@
*
* @param request Request (associated with the response) to log
* @param response Response (associated with the request) to log
- * @param time Time taken to process the request/response in milliseconds (use 0 if not known)
+ * @param time Time taken to process the request/response in nanoseconds (use 0 if not known)
* @param useDefault Flag that indicates that the request/response should be logged in the engine's default access
* log
*/
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ContainerEvent.java tomcat10-10.1.52/java/org/apache/catalina/ContainerEvent.java
--- tomcat10-10.1.40/java/org/apache/catalina/ContainerEvent.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ContainerEvent.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
/**
* General event for notifying listeners of significant changes on a Container.
- *
- * @author Craig R. McClanahan
*/
public final class ContainerEvent extends EventObject {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ContainerListener.java tomcat10-10.1.52/java/org/apache/catalina/ContainerListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/ContainerListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ContainerListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
/**
* Interface defining a listener for significant Container generated events. Note that "container start" and "container
* stop" events are normally LifecycleEvents, not ContainerEvents.
- *
- * @author Craig R. McClanahan
*/
public interface ContainerListener {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ContainerServlet.java tomcat10-10.1.52/java/org/apache/catalina/ContainerServlet.java
--- tomcat10-10.1.40/java/org/apache/catalina/ContainerServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ContainerServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
* A ContainerServlet is a servlet that has access to Catalina internal functionality, and is loaded from the
* Catalina class loader instead of the web application class loader. The property setter methods must be called by the
* container whenever a new instance of this servlet is put into service.
- *
- * @author Craig R. McClanahan
*/
public interface ContainerServlet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Context.java tomcat10-10.1.52/java/org/apache/catalina/Context.java
--- tomcat10-10.1.40/java/org/apache/catalina/Context.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Context.java 2026-01-23 19:33:36.000000000 +0000
@@ -61,8 +61,6 @@
* The child containers attached to a Context are generally implementations of Wrapper (representing individual servlet
* definitions).
*
- *
- * @author Craig R. McClanahan
*/
public interface Context extends Container, ContextBind {
@@ -1100,7 +1098,7 @@
/**
* @return the array of watched resources for this Context. If none are defined, a zero length array will be
- * returned.
+ * returned.
*/
String[] findWatchedResources();
@@ -1116,7 +1114,7 @@
/**
* @return the array of welcome files defined for this Context. If none are defined, a zero-length array is
- * returned.
+ * returned.
*/
String[] findWelcomeFiles();
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Engine.java tomcat10-10.1.52/java/org/apache/catalina/Engine.java
--- tomcat10-10.1.40/java/org/apache/catalina/Engine.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Engine.java 2026-01-23 19:33:36.000000000 +0000
@@ -32,8 +32,6 @@
*
* If used, an Engine is always the top level Container in a Catalina hierarchy. Therefore, the implementation's
* setParent() method should throw IllegalArgumentException.
- *
- * @author Craig R. McClanahan
*/
public interface Engine extends Container {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Globals.java tomcat10-10.1.52/java/org/apache/catalina/Globals.java
--- tomcat10-10.1.40/java/org/apache/catalina/Globals.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Globals.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,8 +18,6 @@
/**
* Global constants that are applicable to multiple packages within Catalina.
- *
- * @author Craig R. McClanahan
*/
public final class Globals {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Group.java tomcat10-10.1.52/java/org/apache/catalina/Group.java
--- tomcat10-10.1.40/java/org/apache/catalina/Group.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Group.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,8 +25,6 @@
* group inherits the {@link Role}s assigned to the group.
*
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public interface Group extends Principal {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Host.java tomcat10-10.1.52/java/org/apache/catalina/Host.java
--- tomcat10-10.1.40/java/org/apache/catalina/Host.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Host.java 2026-01-23 19:33:36.000000000 +0000
@@ -37,8 +37,6 @@
*
* The child containers attached to a Host are generally implementations of Context (representing an individual servlet
* context).
- *
- * @author Craig R. McClanahan
*/
public interface Host extends Container {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Lifecycle.java tomcat10-10.1.52/java/org/apache/catalina/Lifecycle.java
--- tomcat10-10.1.40/java/org/apache/catalina/Lifecycle.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Lifecycle.java 2026-01-23 19:33:36.000000000 +0000
@@ -75,8 +75,6 @@
*
* The {@link LifecycleEvent}s fired during state changes are defined in the methods that trigger the changed. No
* {@link LifecycleEvent}s are fired if the attempted transition is not valid.
- *
- * @author Craig R. McClanahan
*/
public interface Lifecycle {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/LifecycleEvent.java tomcat10-10.1.52/java/org/apache/catalina/LifecycleEvent.java
--- tomcat10-10.1.40/java/org/apache/catalina/LifecycleEvent.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/LifecycleEvent.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
/**
* General event for notifying listeners of significant changes on a component that implements the Lifecycle interface.
- *
- * @author Craig R. McClanahan
*/
public final class LifecycleEvent extends EventObject {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/LifecycleException.java tomcat10-10.1.52/java/org/apache/catalina/LifecycleException.java
--- tomcat10-10.1.40/java/org/apache/catalina/LifecycleException.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/LifecycleException.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
/**
* General purpose exception that is thrown to indicate a lifecycle related problem. Such exceptions should generally be
* considered fatal to the operation of the application containing this component.
- *
- * @author Craig R. McClanahan
*/
public final class LifecycleException extends Exception {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/LifecycleListener.java tomcat10-10.1.52/java/org/apache/catalina/LifecycleListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/LifecycleListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/LifecycleListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,11 +18,9 @@
/**
- * Interface defining a listener for significant events (including "component start" and "component stop") generated by a
- * component that implements the Lifecycle interface. The listener will be fired after the associated state change has
+ * Interface defining a listener for significant events (including "component start" and "component stop") generated by
+ * a component that implements the Lifecycle interface. The listener will be fired after the associated state change has
* taken place.
- *
- * @author Craig R. McClanahan
*/
public interface LifecycleListener {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Loader.java tomcat10-10.1.52/java/org/apache/catalina/Loader.java
--- tomcat10-10.1.40/java/org/apache/catalina/Loader.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Loader.java 2026-01-23 19:33:36.000000000 +0000
@@ -35,8 +35,6 @@
*
Based on a policy chosen by the implementation, must call the Context.reload() method on the owning
* Context when a change to one or more of the class files loaded by this class loader is detected.
*
- *
- * @author Craig R. McClanahan
*/
public interface Loader {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Manager.java tomcat10-10.1.52/java/org/apache/catalina/Manager.java
--- tomcat10-10.1.40/java/org/apache/catalina/Manager.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Manager.java 2026-01-23 19:33:36.000000000 +0000
@@ -31,8 +31,6 @@
*
Must allow a call to stop() to be followed by a call to start() on the same
* Manager instance.
*
- *
- * @author Craig R. McClanahan
*/
public interface Manager {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Pipeline.java tomcat10-10.1.52/java/org/apache/catalina/Pipeline.java
--- tomcat10-10.1.40/java/org/apache/catalina/Pipeline.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Pipeline.java 2026-01-23 19:33:36.000000000 +0000
@@ -19,21 +19,15 @@
import java.util.Set;
/**
- *
* Interface describing a collection of Valves that should be executed in sequence when the invoke() method
* is invoked. It is required that a Valve somewhere in the pipeline (usually the last one) must process the request and
* create the corresponding response, rather than trying to pass the request on.
- *
*
* There is generally a single Pipeline instance associated with each Container. The container's normal request
* processing functionality is generally encapsulated in a container-specific Valve, which should always be executed at
* the end of a pipeline. To facilitate this, the setBasic() method is provided to set the Valve instance
* that will always be executed last. Other Valves will be executed in the order that they were added, before the basic
* Valve is executed.
- *
- *
- * @author Craig R. McClanahan
- * @author Peter Donald
*/
public interface Pipeline extends Contained {
@@ -81,7 +75,7 @@
/**
* @return the array of Valves in the pipeline associated with this Container, including the basic Valve (if any).
- * If there are no such Valves, a zero-length array is returned.
+ * If there are no such Valves, a zero-length array is returned.
*/
Valve[] getValves();
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Realm.java tomcat10-10.1.52/java/org/apache/catalina/Realm.java
--- tomcat10-10.1.40/java/org/apache/catalina/Realm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Realm.java 2026-01-23 19:33:36.000000000 +0000
@@ -32,8 +32,6 @@
* A Realm is a read-only facade for an underlying security realm used to authenticate individual users, and
* identify the security roles associated with those users. Realms can be attached at any Container level, but will
* typically only be attached to a Context, or higher level, Container.
- *
- * @author Craig R. McClanahan
*/
public interface Realm extends Contained {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Role.java tomcat10-10.1.52/java/org/apache/catalina/Role.java
--- tomcat10-10.1.40/java/org/apache/catalina/Role.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Role.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
* Principals.
*
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public interface Role extends Principal {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Server.java tomcat10-10.1.52/java/org/apache/catalina/Server.java
--- tomcat10-10.1.40/java/org/apache/catalina/Server.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Server.java 2026-01-23 19:33:36.000000000 +0000
@@ -34,8 +34,6 @@
* In between, the implementation must open a server socket on the port number specified by the port
* property. When a connection is accepted, the first line is read and compared with the specified shutdown command. If
* the command matches, shutdown of the server is initiated.
- *
- * @author Craig R. McClanahan
*/
public interface Server extends Lifecycle {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Service.java tomcat10-10.1.52/java/org/apache/catalina/Service.java
--- tomcat10-10.1.40/java/org/apache/catalina/Service.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Service.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
*
* A given JVM can contain any number of Service instances; however, they are completely independent of each other and
* share only the basic JVM facilities and classes on the system class path.
- *
- * @author Craig R. McClanahan
*/
public interface Service extends Lifecycle {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Session.java tomcat10-10.1.52/java/org/apache/catalina/Session.java
--- tomcat10-10.1.40/java/org/apache/catalina/Session.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Session.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* A Session is the Catalina-internal facade for an HttpSession that is used to maintain state
* information between requests for a particular user of a web application.
- *
- * @author Craig R. McClanahan
*/
public interface Session {
@@ -58,6 +56,10 @@
*/
String SESSION_PASSIVATED_EVENT = "passivateSession";
+ /**
+ * The SessionEvent event type when a session changes its sessionId.
+ */
+ String SESSION_CHANGED_ID_EVENT = "changeSessionId";
// ------------------------------------------------------------- Properties
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/SessionEvent.java tomcat10-10.1.52/java/org/apache/catalina/SessionEvent.java
--- tomcat10-10.1.40/java/org/apache/catalina/SessionEvent.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/SessionEvent.java 2026-01-23 19:33:36.000000000 +0000
@@ -22,8 +22,6 @@
/**
* General event for notifying listeners of significant changes on a Session.
- *
- * @author Craig R. McClanahan
*/
public final class SessionEvent extends EventObject {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/SessionListener.java tomcat10-10.1.52/java/org/apache/catalina/SessionListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/SessionListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/SessionListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,8 +21,6 @@
/**
* Interface defining a listener for significant Session generated events.
- *
- * @author Craig R. McClanahan
*/
public interface SessionListener extends EventListener {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Store.java tomcat10-10.1.52/java/org/apache/catalina/Store.java
--- tomcat10-10.1.40/java/org/apache/catalina/Store.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Store.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,13 +25,9 @@
* A Store is the abstraction of a Catalina component that provides persistent storage and loading of Sessions
* and their associated user data. Implementations are free to save and load the Sessions to any media they wish, but it
* is assumed that saved Sessions are persistent across server or context restarts.
- *
- * @author Craig R. McClanahan
*/
public interface Store {
- // ------------------------------------------------------------- Properties
-
/**
* @return the Manager instance associated with this Store.
*/
@@ -54,9 +50,6 @@
int getSize() throws IOException;
- // --------------------------------------------------------- Public Methods
-
-
/**
* Add a property change listener to this component.
*
@@ -77,6 +70,11 @@
/**
* Load and return the Session associated with the specified session identifier from this Store, without removing
* it. If there is no such stored Session, return null.
+ *
+ * Implementations should expect, and correctly handle, concurrent calls to any method but in particular calls to
+ * {@code #load(String)}, {@code #save(Session)} and {@code #remove(String)} for the same session.
+ *
+ * The session ID is user provided so stores must treat it as untrusted data.
*
* @param id Session identifier of the session to load
*
@@ -91,6 +89,11 @@
/**
* Remove the Session with the specified session identifier from this Store, if present. If no such Session is
* present, this method takes no action.
+ *
+ * Implementations should expect, and correctly handle, concurrent calls to any method but in particular calls to
+ * {@code #load(String)}, {@code #save(Session)} and {@code #remove(String)} for the same session.
+ *
+ * The session ID is user provided so stores must treat it as untrusted data.
*
* @param id Session identifier of the Session to be removed
*
@@ -118,12 +121,13 @@
/**
* Save the specified Session into this Store. Any previously saved information for the associated session
* identifier is replaced.
+ *
+ * Implementations should expect, and correctly handle, concurrent calls to any method but in particular calls to
+ * {@code #load(String)}, {@code #save(Session)} and {@code #remove(String)} for the same session.
*
* @param session Session to be saved
*
* @exception IOException if an input/output error occurs
*/
void save(Session session) throws IOException;
-
-
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/User.java tomcat10-10.1.52/java/org/apache/catalina/User.java
--- tomcat10-10.1.40/java/org/apache/catalina/User.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/User.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
* {@link Group}s through which they inherit additional security roles, and is optionally assigned a set of specific
* {@link Role}s.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public interface User extends Principal {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/UserDatabase.java tomcat10-10.1.52/java/org/apache/catalina/UserDatabase.java
--- tomcat10-10.1.40/java/org/apache/catalina/UserDatabase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/UserDatabase.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
* along with definitions of corresponding {@link Role}s, and referenced by a {@link Realm} for authentication and
* access control.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public interface UserDatabase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Valve.java tomcat10-10.1.52/java/org/apache/catalina/Valve.java
--- tomcat10-10.1.40/java/org/apache/catalina/Valve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Valve.java 2026-01-23 19:33:36.000000000 +0000
@@ -24,17 +24,12 @@
import org.apache.catalina.connector.Response;
/**
- *
* A Valve is a request processing component associated with a particular Container. A series of Valves are
* generally associated with each other into a Pipeline. The detailed contract for a Valve is included in the
* description of the invoke() method below.
- *
+ *
* HISTORICAL NOTE: The "Valve" name was assigned to this concept because a valve is what you use in a real world
* pipeline to control and/or modify flows through it.
- *
- * @author Craig R. McClanahan
- * @author Gunnar Rjnning
- * @author Peter Donald
*/
public interface Valve {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/WebResourceRoot.java tomcat10-10.1.52/java/org/apache/catalina/WebResourceRoot.java
--- tomcat10-10.1.40/java/org/apache/catalina/WebResourceRoot.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/WebResourceRoot.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,6 +21,8 @@
import java.util.List;
import java.util.Set;
+import org.apache.catalina.util.ResourceSet;
+
/**
* Represents the complete set of resources for a web application. The resources for a web application consist of
* multiple ResourceSets and when looking for a Resource, the ResourceSets are processed in the following order:
@@ -95,8 +97,8 @@
* calls to this method until the web application is reloaded. No guarantee is made as to what the search order for
* JAR files may be.
*
- * @param path The path of the class loader resource of interest relative to the root of class loader resources
- * for this web application.
+ * @param path The path of the class loader resource of interest relative to the root of class loader resources for
+ * this web application.
*
* @return The object that represents the class loader resource at the given path
*/
@@ -246,14 +248,16 @@
void setContext(Context context);
/**
- * Configure if this resources allow the use of symbolic links.
+ * Configure if this web application allows the use of symbolic links by default. Individual {@link ResourceSet}s
+ * may override this setting.
*
* @param allowLinking true if symbolic links are allowed.
*/
void setAllowLinking(boolean allowLinking);
/**
- * Determine if this resources allow the use of symbolic links.
+ * Determine if this web application allows the use of symbolic links by default. Individual {@link ResourceSet}s
+ * may override this setting.
*
* @return true if symbolic links are allowed
*/
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/WebResourceSet.java tomcat10-10.1.52/java/org/apache/catalina/WebResourceSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/WebResourceSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/WebResourceSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -135,4 +135,19 @@
* resources.
*/
void gc();
+
+ /**
+ * Configure if this {@code ResourceSet} allows the use of symbolic links.
+ *
+ * @param allowLinking true if symbolic links are allowed.
+ */
+ void setAllowLinking(boolean allowLinking);
+
+ /**
+ * Determine if this {@code ResourceSet} allows the use of symbolic links. If {@link #setAllowLinking(boolean)} has
+ * not been called for this instance, the value of {@link WebResourceRoot#getAllowLinking()} is returned.
+ *
+ * @return true if symbolic links are allowed
+ */
+ boolean getAllowLinking();
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/Wrapper.java tomcat10-10.1.52/java/org/apache/catalina/Wrapper.java
--- tomcat10-10.1.40/java/org/apache/catalina/Wrapper.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/Wrapper.java 2026-01-23 19:33:36.000000000 +0000
@@ -36,8 +36,6 @@
*
* Child Containers are not allowed on Wrapper implementations, so the addChild() method should throw an
* IllegalArgumentException.
- *
- * @author Craig R. McClanahan
*/
public interface Wrapper extends Container {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/AbstractCatalinaTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/AbstractCatalinaTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/AbstractCatalinaTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/AbstractCatalinaTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -28,6 +28,7 @@
import java.net.URLConnection;
import org.apache.catalina.util.IOTools;
+import org.apache.tomcat.util.http.Method;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
@@ -35,8 +36,6 @@
* Abstract base class for Ant tasks that interact with the Manager web application for dynamically deploying
* and undeploying applications. These tasks require Ant 1.4 or later.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public abstract class AbstractCatalinaTask extends BaseRedirectorHelperTask {
@@ -187,7 +186,7 @@
preAuthenticate();
hconn.setDoOutput(true);
- hconn.setRequestMethod("PUT");
+ hconn.setRequestMethod(Method.PUT);
if (contentType != null) {
hconn.setRequestProperty("Content-Type", contentType);
}
@@ -198,7 +197,7 @@
}
} else {
hconn.setDoOutput(false);
- hconn.setRequestMethod("GET");
+ hconn.setRequestMethod(Method.GET);
}
hconn.setRequestProperty("User-Agent", "Catalina-Ant-Task/1.0");
@@ -297,7 +296,7 @@
hconn.setDoInput(true);
hconn.setUseCaches(false);
hconn.setDoOutput(false);
- hconn.setRequestMethod("OPTIONS");
+ hconn.setRequestMethod(Method.OPTIONS);
hconn.setRequestProperty("User-Agent", "Catalina-Ant-Task/1.0");
// Establish the connection with the server
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -30,14 +30,12 @@
/**
* Abstract base class to add output redirection support for Catalina Ant tasks. These tasks require Ant 1.5 or later.
*
- * WARNING: due to dependency chain, Ant could call a Task more than once and this can affect the output
- * redirection when configured. If you are collecting the output in a property, it will collect the output of only the
- * first run, since Ant properties are immutable and once created they cannot be changed.
+ * WARNING: due to dependency chain, Ant could call a Task more than once and this can affect the
+ * output redirection when configured. If you are collecting the output in a property, it will collect the output of
+ * only the first run, since Ant properties are immutable and once created they cannot be changed.
* If you are collecting output in a file the file will be overwritten with the output of the last run, unless you set
* append="true", in which case each run will append it's output to the file.
*
- * @author Gabriele Garuglieri
- *
* @since 5.5
*/
public abstract class BaseRedirectorHelperTask extends Task {
@@ -218,8 +216,8 @@
redirectOutput = true;
}
/*
- * Due to dependency chain, Ant could call the Task more than once, this is to prevent that we attempt to configure
- * uselessly more than once the Redirector.
+ * Due to dependency chain, Ant could call the Task more than once, this is to prevent that we attempt to
+ * configure uselessly more than once the Redirector.
*/
redirectorConfigured = true;
}
@@ -256,8 +254,8 @@
log("Error closing redirector: " + ioe.getMessage(), Project.MSG_ERR);
}
/*
- * Due to dependency chain, Ant could call the Task more than once, this is to prevent that we attempt to reuse the
- * previously closed Streams.
+ * Due to dependency chain, Ant could call the Task more than once, this is to prevent that we attempt to reuse
+ * the previously closed Streams.
*/
redirectOutStream = null;
redirectOutPrintStream = null;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/DeployTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/DeployTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/DeployTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/DeployTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -32,8 +32,6 @@
/**
* Ant task that implements the /deploy command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class DeployTask extends AbstractCatalinaCommandTask {
@@ -145,15 +143,15 @@
FileChannel fsChannel = fsInput.getChannel();
contentLength = fsChannel.size();
stream = new BufferedInputStream(fsInput, 1024);
- } catch (IOException e) {
+ } catch (IOException ioe) {
if (fsInput != null) {
try {
fsInput.close();
- } catch (IOException ioe) {
+ } catch (IOException ignore) {
// Ignore
}
}
- throw new BuildException(e);
+ throw new BuildException(ioe);
}
}
contentType = "application/octet-stream";
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/JKStatusUpdateTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/JKStatusUpdateTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/JKStatusUpdateTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/JKStatusUpdateTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -24,8 +24,6 @@
/**
* Ant task that implements the /status command, supported by the mod_jk status (1.2.9) application.
*
- * @author Peter Rossbach
- *
* @since 5.5.9
*/
public class JKStatusUpdateTask extends AbstractCatalinaTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/JMXGetTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/JMXGetTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/JMXGetTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/JMXGetTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* Ant task that implements the JMX Get command (/jmxproxy/?get) supported by the Tomcat manager
* application.
- *
- * @author Peter Rossbach
*/
public class JMXGetTask extends AbstractCatalinaTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/JMXQueryTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/JMXQueryTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/JMXQueryTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/JMXQueryTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* Ant task that implements the JMX Query command (/jmxproxy/?qry) supported by the Tomcat manager
* application.
- *
- * @author Vivek Chopra
*/
public class JMXQueryTask extends AbstractCatalinaTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/JMXSetTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/JMXSetTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/JMXSetTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/JMXSetTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* Ant task that implements the JMX Set command (/jmxproxy/?set) supported by the Tomcat manager
* application.
- *
- * @author Vivek Chopra
*/
public class JMXSetTask extends AbstractCatalinaTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/ListTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/ListTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/ListTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/ListTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
/**
* Ant task that implements the /list command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class ListTask extends AbstractCatalinaTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/ReloadTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/ReloadTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/ReloadTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/ReloadTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
/**
* Ant task that implements the /reload command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class ReloadTask extends AbstractCatalinaCommandTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/ResourcesTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/ResourcesTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/ResourcesTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/ResourcesTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* Ant task that implements the /resources command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class ResourcesTask extends AbstractCatalinaTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/ServerinfoTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/ServerinfoTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/ServerinfoTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/ServerinfoTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -16,19 +16,13 @@
*/
package org.apache.catalina.ant;
-
import org.apache.tools.ant.BuildException;
-
/**
* Ant task that implements the /serverinfo command supported by the Tomcat manager application.
- *
- * @author Vivek Chopra
*/
public class ServerinfoTask extends AbstractCatalinaTask {
- // Public Methods
-
/**
* Execute the requested operation.
*
@@ -36,9 +30,7 @@
*/
@Override
public void execute() throws BuildException {
-
super.execute();
execute("/serverinfo");
-
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/SessionsTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/SessionsTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/SessionsTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/SessionsTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -16,18 +16,13 @@
*/
package org.apache.catalina.ant;
-
import org.apache.tools.ant.BuildException;
-
/**
* Ant task that implements the /sessions command supported by the Tomcat manager application.
- *
- * @author Vivek Chopra
*/
public class SessionsTask extends AbstractCatalinaCommandTask {
-
protected String idle = null;
public String getIdle() {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/StartTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/StartTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/StartTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/StartTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
/**
* Ant task that implements the /start command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class StartTask extends AbstractCatalinaCommandTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/StopTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/StopTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/StopTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/StopTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
/**
* Ant task that implements the /stop command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class StopTask extends AbstractCatalinaCommandTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/UndeployTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/UndeployTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/UndeployTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/UndeployTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
/**
* Ant task that implements the /undeploy command, supported by the Tomcat manager application.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class UndeployTask extends AbstractCatalinaCommandTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/ValidatorTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/ValidatorTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/ValidatorTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/ValidatorTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -32,8 +32,6 @@
/**
* Task for validating a web application deployment descriptor, using XML schema validation.
*
- * @author Remy Maucherat
- *
* @since 5.0
*/
public class ValidatorTask extends BaseRedirectorHelperTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java 2026-01-23 19:33:36.000000000 +0000
@@ -77,8 +77,6 @@
* NOTE: For numeric expressions the type must be set and use xml entities as operations.
* As type we currently support long and double.
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorCondition extends JMXAccessorConditionBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -46,16 +46,14 @@
* </jmxCreate/>
*
*
- * WARNINGNot all Tomcat MBeans can create remotely and auto register by its parents! Please, use the MBeanFactory
- * operation to generate valves and realms.
+ * WARNINGNot all Tomcat MBeans can create remotely and auto register by its parents! Please, use the
+ * MBeanFactory operation to generate valves and realms.
*
*
* First call to a remote MBean server save the JMXConnection a reference jmx.server
*
* These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.12
*/
public class JMXAccessorCreateTask extends JMXAccessorTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java 2026-01-23 19:33:36.000000000 +0000
@@ -54,8 +54,6 @@
* </target>
*
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorEqualsCondition extends JMXAccessorConditionBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -49,8 +49,6 @@
*
* These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorGetTask extends JMXAccessorTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -54,6 +54,7 @@
*
*
*
* First call to a remote MBeanserver save the JMXConnection a referenz jmx.server
*
* These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorInvokeTask extends JMXAccessorTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -51,8 +51,6 @@
* The property manager.length show the size of the result and with manager.[0..length].name the resulted ObjectNames
* are saved. These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorQueryTask extends JMXAccessorTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -55,8 +55,6 @@
*
* These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorSetTask extends JMXAccessorTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -77,8 +77,6 @@
* execute when property exist and with unless when property not exists.
* NOTE : These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.10
*/
public class JMXAccessorTask extends BaseRedirectorHelperTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
--- tomcat10-10.1.40/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java 2026-01-23 19:33:36.000000000 +0000
@@ -45,8 +45,6 @@
*
* These tasks require Ant 1.6 or later interface.
*
- * @author Peter Rossbach
- *
* @since 5.5.12
*/
public class JMXAccessorUnregisterTask extends JMXAccessorTask {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/AuthenticatorBase.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/AuthenticatorBase.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/AuthenticatorBase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/AuthenticatorBase.java 2026-01-23 19:33:36.000000000 +0000
@@ -70,6 +70,7 @@
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.res.StringManager;
@@ -85,8 +86,6 @@
*
* USAGE CONSTRAINT: This Valve is only useful when processing HTTP requests. Requests of any other type will
* simply be passed through.
- *
- * @author Craig R. McClanahan
*/
public abstract class AuthenticatorBase extends ValveBase implements Authenticator, RegistrationListener {
@@ -211,7 +210,6 @@
* {@code remote-user} and {@code auth-type} to a reverse proxy. This is useful, e.g., for access log consistency or
* other decisions to make.
*/
-
protected boolean sendAuthInfoResponseHeaders = false;
protected SessionIdGeneratorBase sessionIdGenerator = null;
@@ -221,6 +219,8 @@
*/
protected SingleSignOn sso = null;
+ private SsoReauthenticationMode ssoReauthenticationMode = SsoReauthenticationMode.DEFAULT;
+
private AllowCorsPreflight allowCorsPreflight = AllowCorsPreflight.NEVER;
private volatile String jaspicAppContextID = null;
@@ -230,6 +230,15 @@
// ------------------------------------------------------------- Properties
+ public String getSsoReauthenticationMode() {
+ return ssoReauthenticationMode.name().toLowerCase(Locale.ENGLISH);
+ }
+
+ public void setSsoReauthenticationMode(String ssoReauthenticationMode) {
+ this.ssoReauthenticationMode =
+ SsoReauthenticationMode.valueOf(ssoReauthenticationMode.trim().toUpperCase(Locale.ENGLISH));
+ }
+
public String getAllowCorsPreflight() {
return allowCorsPreflight.name().toLowerCase(Locale.ENGLISH);
}
@@ -486,7 +495,7 @@
// Make sure that constrained resources are not cached by web proxies
// or browsers as caching can provide a security hole
- if (constraints != null && disableProxyCaching && !"POST".equalsIgnoreCase(request.getMethod())) {
+ if (constraints != null && disableProxyCaching && !Method.POST.equals(request.getMethod())) {
if (securePagesWithPragma) {
// Note: These can cause problems with downloading files with IE
response.setHeader("Pragma", "No-cache");
@@ -609,7 +618,7 @@
if (allowCorsPreflight != AllowCorsPreflight.NEVER) {
// First check to see if this is a CORS Preflight request
// This is a subset of the tests in CorsFilter.checkRequestType
- if ("OPTIONS".equals(request.getMethod())) {
+ if (Method.OPTIONS.equals(request.getMethod())) {
String originHeader = request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN);
if (originHeader != null && !originHeader.isEmpty() && RequestUtil.isValidOrigin(originHeader) &&
!RequestUtil.isSameOrigin(request, originHeader)) {
@@ -726,12 +735,13 @@
Class> clazz = null;
try {
clazz = Class.forName(jaspicCallbackHandlerClass, true, Thread.currentThread().getContextClassLoader());
- } catch (ClassNotFoundException e) {
- // Proceed with the retry below
+ } catch (ClassNotFoundException ignore) {
+ // Not found in the context class loader (web application class loader). Re-try below.
}
try {
if (clazz == null) {
+ // Look in the same class loader that loaded this class - usually Tomcat's common loader.
clazz = Class.forName(jaspicCallbackHandlerClass);
}
callbackHandler = (CallbackHandler) clazz.getConstructor().newInstance();
@@ -878,40 +888,87 @@
* Check to see if the user has already been authenticated earlier in the processing chain or if there is enough
* information available to authenticate the user without requiring further user interaction.
*
- * @param request The current request
- * @param response The current response
- * @param useSSO Should information available from SSO be used to attempt to authenticate the current user?
+ * @param request The current request
+ * @param response The current response
+ * @param useSsoCachedUserAndPassword Should the user and password available from SSO be used to attempt to
+ * authenticate the current user?
*
* @return true if the user was authenticated via the cache, otherwise false
*/
- protected boolean checkForCachedAuthentication(Request request, HttpServletResponse response, boolean useSSO) {
+ protected boolean checkForCachedAuthentication(Request request, HttpServletResponse response,
+ boolean useSsoCachedUserAndPassword) {
+
+ /*
+ * There are two methods for authentication caching implemented by the SSO Valve. The first caches the
+ * authenticated Principal returned by the Realm. The second caches the user name and password passed to the
+ * Realm that were used for authentication.
+ *
+ * If cached authentication is not available or fails for any reason, the Authenticator will attempt the normal
+ * authentication process for the Authenticator.
+ *
+ * Which cached authentication methods are used depends on the configuration of the SSO Valve and/or the
+ * Authenticator.
+ *
+ * If the SSO Valve is configured to require re-authentication, any cached Principal will not be used unless the
+ * Authenticator is explicitly configured (via ssoReauthenticationMode) to use it.
+ *
+ * If the SSO Valve is configured to require re-authentication, whether the cached user name and password can be
+ * used will be determined by the calling Authenticator type unless the Authenticator's ssoReauthenticationMode
+ * is explicitly configured.
+ */
+
+ // Determine which - if any - checks for cached authentication will be made.
+ boolean checkPrincipal = false;
+ boolean checkPassword = false;
- // Has the user already been authenticated?
- Principal principal = request.getUserPrincipal();
+ // Will be null if SSO is not configured or there is no current SSO session
String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
- if (principal != null) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("authenticator.check.found", principal.getName()));
- }
- // Associate the session with any existing SSO session. Even if
- // useSSO is false, this will ensure coordinated session
- // invalidation at log out.
+
+ if (sso == null) {
+ // There is no SSO - check in case some other component has set the Principal
+ checkPrincipal = true;
+ } else if (ssoReauthenticationMode == SsoReauthenticationMode.DEFAULT && !sso.getRequireReauthentication() ||
+ ssoReauthenticationMode == SsoReauthenticationMode.PRINCIPAL) {
+ checkPrincipal = true;
+ // If checkPrincipal is enabled then checkPassword is enabled if there is an SSO session
if (ssoId != null) {
- associate(ssoId, request.getSessionInternal(true));
+ checkPassword = true;
}
- return true;
+ } else if (ssoId != null && (ssoReauthenticationMode == SsoReauthenticationMode.PASSWORD ||
+ sso.getRequireReauthentication() && useSsoCachedUserAndPassword)) {
+ checkPassword = true;
}
- // Is there an SSO session against which we can try to reauthenticate?
- if (useSSO && ssoId != null) {
+ // Check for a cached Principal. Most likely from SSO but could be another component.
+ if (checkPrincipal) {
+ if (ssoId != null && sso != null && sso.getRequireReauthentication()) {
+ // There is a valid SSO session but SSO Valve won't have cached the Principal.
+ sso.populateRequestFromSsoEntry(request, ssoId);
+ }
+
+ // Has the user already been authenticated?
+ Principal principal = request.getUserPrincipal();
+ if (principal != null) {
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("authenticator.check.found", principal.getName()));
+ }
+ // Associate the session with any existing SSO session. Even if
+ // useSSO is false, this will ensure coordinated session
+ // invalidation at log out.
+ if (ssoId != null) {
+ associate(ssoId, request.getSessionInternal(true));
+ }
+ return true;
+ }
+ }
+
+ // Check for a user and password cached by SSO
+ if (checkPassword) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("authenticator.check.sso", ssoId));
}
/*
- * Try to reauthenticate using data cached by SSO. If this fails, either the original SSO logon was of
- * DIGEST or SSL (which we can't reauthenticate ourselves because there is no cached username and password),
- * or the realm denied the user's reauthentication for some reason. In either case we have to prompt the
- * user for a logon
+ * Try to reauthenticate using data cached by SSO. If this fails we have to prompt the user for credentials.
*/
if (reauthenticateFromSSO(ssoId, request)) {
return true;
@@ -1294,4 +1351,12 @@
FILTER,
ALWAYS
}
+
+
+ protected enum SsoReauthenticationMode {
+ DEFAULT,
+ PRINCIPAL,
+ PASSWORD,
+ FULL
+ }
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/BasicAuthenticator.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/BasicAuthenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/BasicAuthenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/BasicAuthenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -34,8 +34,6 @@
/**
* An Authenticator and Valve implementation of HTTP BASIC Authentication, as outlined in RFC 7617: "The
* 'Basic' HTTP Authentication Scheme"
- *
- * @author Craig R. McClanahan
*/
public class BasicAuthenticator extends AuthenticatorBase {
@@ -116,7 +114,7 @@
}
} catch (IllegalArgumentException iae) {
if (log.isDebugEnabled()) {
- log.debug(sm.getString("basicAuthenticator.invalidAuthorization", iae.getMessage()));
+ log.debug(sm.getString("basicAuthenticator.invalidAuthorization"), iae);
}
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/DigestAuthenticator.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/DigestAuthenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/DigestAuthenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/DigestAuthenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -47,9 +47,6 @@
/**
* An Authenticator and Valve implementation of HTTP DIGEST Authentication, as outlined in RFC 7616: "HTTP
* Digest Authentication"
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class DigestAuthenticator extends AuthenticatorBase {
@@ -266,14 +263,16 @@
@Override
protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
- // NOTE: We don't try to reauthenticate using any existing SSO session,
- // because that will only work if the original authentication was
- // BASIC or FORM, which are less secure than the DIGEST auth-type
- // specified for this webapp
- //
- // Change to true below to allow previous FORM or BASIC authentications
- // to authenticate users for this webapp
- // TODO make this a configurable attribute (in SingleSignOn??)
+ /*
+ * Reauthentication using the cached user name and password (if any) is not enabled for DIGEST authentication.
+ * This was an historical design decision made because DIGEST authentication is viewed as more secure than
+ * BASIC/FORM.
+ *
+ * However, reauthentication was introduced to handle the case where the Realm took additional actions on
+ * authentication. Reauthenticating with the cached user name and password should be sufficient for DIGEST in
+ * that scenario. However, the original behaviour to reauthenticate has been retained in case of any (very
+ * unlikely) backwards compatibility issues.
+ */
if (checkForCachedAuthentication(request, response, false)) {
return true;
}
@@ -539,7 +538,7 @@
Map directives;
try {
directives = Authorization.parseAuthorizationDigest(new StringReader(authorization));
- } catch (IOException e) {
+ } catch (IOException ioe) {
return false;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/FormAuthenticator.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/FormAuthenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/FormAuthenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/FormAuthenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -42,14 +42,12 @@
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.http.MimeHeaders;
/**
* An Authenticator and Valve implementation of FORM BASED Authentication, as described in the Servlet API
* Specification.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class FormAuthenticator extends AuthenticatorBase {
@@ -247,7 +245,7 @@
try {
saveRequest(request, session);
} catch (IOException ioe) {
- log.debug(sm.getString("authenticator.requestBodyTooBig"));
+ log.debug(sm.getString("authenticator.requestBodyTooBig"), ioe);
response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("authenticator.requestBodyTooBig"));
return false;
}
@@ -303,7 +301,7 @@
// the landing page
String uri = request.getContextPath() + landingPage;
SavedRequest saved = new SavedRequest();
- saved.setMethod("GET");
+ saved.setMethod(Method.GET);
saved.setRequestURI(uri);
saved.setDecodedRequestURI(uri);
request.getSessionInternal(true).setNote(Constants.FORM_REQUEST_NOTE, saved);
@@ -328,7 +326,7 @@
// the landing page
String uri = request.getContextPath() + landingPage;
SavedRequest saved = new SavedRequest();
- saved.setMethod("GET");
+ saved.setMethod(Method.GET);
saved.setRequestURI(uri);
saved.setDecodedRequestURI(uri);
session.setNote(Constants.FORM_REQUEST_NOTE, saved);
@@ -364,15 +362,7 @@
// a resource is protected for some HTTP methods but not protected for
// GET which is used after authentication when redirecting to the
// protected resource.
- // TODO: This is similar to the FormAuthenticator.matchRequest() logic
- // Is there a way to remove the duplication?
- Session session = request.getSessionInternal(false);
- if (session != null) {
- SavedRequest savedRequest = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
- return savedRequest != null && decodedRequestURI.equals(savedRequest.getDecodedRequestURI());
- }
-
- return false;
+ return matchRequest(request, false);
}
@@ -448,7 +438,7 @@
// Always use GET for the login page, regardless of the method used
String oldMethod = request.getMethod();
- request.getCoyoteRequest().method().setString("GET");
+ request.getCoyoteRequest().setMethod(Method.GET);
RequestDispatcher disp = context.getServletContext().getRequestDispatcher(loginPage);
try {
@@ -464,7 +454,7 @@
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
} finally {
// Restore original method so that it is written into access log
- request.getCoyoteRequest().method().setString(oldMethod);
+ request.getCoyoteRequest().setMethod(oldMethod);
}
}
@@ -506,15 +496,21 @@
}
+ protected boolean matchRequest(Request request) {
+ return matchRequest(request, true);
+ }
+
/**
* Does this request match the saved one (so that it must be the redirect we signaled after successful
* authentication?)
*
* @param request The request to be verified
+ * @param strict true to check for a valid Principal and valid Session ID, false to only
+ * check for a valid saved request and matching URI
*
* @return true if the requests matched the saved one
*/
- protected boolean matchRequest(Request request) {
+ protected boolean matchRequest(Request request, boolean strict) {
// Has a session been created?
Session session = request.getSessionInternal(false);
if (session == null) {
@@ -527,17 +523,19 @@
return false;
}
- // Is there a saved principal?
- if (cache && session.getPrincipal() == null || !cache && request.getPrincipal() == null) {
- return false;
- }
-
- // Does session id match?
- if (getChangeSessionIdOnAuthentication()) {
- String expectedSessionId = (String) session.getNote(Constants.SESSION_ID_NOTE);
- if (expectedSessionId == null || !expectedSessionId.equals(request.getRequestedSessionId())) {
+ if (strict) {
+ // Is there a saved principal?
+ if (cache && session.getPrincipal() == null || !cache && request.getPrincipal() == null) {
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?
@@ -590,7 +588,7 @@
String method = saved.getMethod();
MimeHeaders rmh = request.getCoyoteRequest().getMimeHeaders();
rmh.recycle();
- boolean cacheable = "GET".equalsIgnoreCase(method) || "HEAD".equalsIgnoreCase(method);
+ boolean cacheable = Method.GET.equals(method) || Method.HEAD.equals(method);
Iterator names = saved.getHeaderNames();
while (names.hasNext()) {
String name = names.next();
@@ -624,7 +622,7 @@
// If no content type specified, use default for POST
String savedContentType = saved.getContentType();
- if (savedContentType == null && "POST".equalsIgnoreCase(method)) {
+ if (savedContentType == null && Method.POST.equals(method)) {
savedContentType = Globals.CONTENT_TYPE_FORM_URL_ENCODING;
}
@@ -632,7 +630,7 @@
request.getCoyoteRequest().setContentType(contentType);
}
- request.getCoyoteRequest().method().setString(method);
+ request.getCoyoteRequest().setMethod(method);
// The method, URI, queryString and protocol are normally stored as
// bytes in the HttpInputBuffer and converted lazily to String. At this
// point, the method has already been set as String in the line above
@@ -646,8 +644,8 @@
request.getCoyoteRequest().queryString().toStringType();
request.getCoyoteRequest().protocol().toStringType();
- if (saved.getOriginalMaxInactiveInterval() > 0) {
- session.setMaxInactiveInterval(saved.getOriginalMaxInactiveInterval());
+ if (saved.getOriginalMaxInactiveIntervalOptional() != null) {
+ session.setMaxInactiveInterval(saved.getOriginalMaxInactiveIntervalOptional().intValue());
}
return true;
@@ -719,17 +717,20 @@
if (session instanceof HttpSession) {
if (((HttpSession) session).isNew()) {
int originalMaxInactiveInterval = session.getMaxInactiveInterval();
- if (originalMaxInactiveInterval > getAuthenticationSessionTimeout()) {
+ if (originalMaxInactiveInterval > getAuthenticationSessionTimeout() ||
+ originalMaxInactiveInterval <= 0) {
saved.setOriginalMaxInactiveInterval(originalMaxInactiveInterval);
session.setMaxInactiveInterval(getAuthenticationSessionTimeout());
}
- } else if (previousSavedRequest != null && previousSavedRequest.getOriginalMaxInactiveInterval() > 0) {
+ } else if (previousSavedRequest != null &&
+ previousSavedRequest.getOriginalMaxInactiveIntervalOptional() != null) {
/*
* The user may have refreshed the browser page during authentication. Transfer the original max
* inactive interval from previous saved request to current one else, once authentication is completed,
- * the session will retain the the shorter authentication session timeout
+ * the session will retain the shorter authentication session timeout
*/
- saved.setOriginalMaxInactiveInterval(previousSavedRequest.getOriginalMaxInactiveInterval());
+ saved.setOriginalMaxInactiveInterval(
+ previousSavedRequest.getOriginalMaxInactiveIntervalOptional().intValue());
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings.properties tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -42,7 +42,7 @@
authenticator.userDataPermissionFail=User data does not comply with the constraints of the resource
authenticator.userPermissionFail=User [{0}] does not have authorization to access the resource
-basicAuthenticator.invalidAuthorization=Invalid Authorization: [{0}]
+basicAuthenticator.invalidAuthorization=Invalid Authorization header
basicAuthenticator.invalidCharset=The only permitted values are null, the empty string or UTF-8
basicAuthenticator.notBase64=Basic Authorization credentials are not Base64
basicAuthenticator.notBasic=Authorization header method is not ''Basic''
@@ -76,9 +76,12 @@
singleSignOn.debug.principalNotFound=SSO did not find a cached Principal. Erasing SSO cookie for session [{0}]
singleSignOn.debug.register=SSO registering SSO session [{0}] for user [{1}] with authentication type [{2}]
singleSignOn.debug.removeSession=SSO removing application session [{0}] from SSO session [{1}]
+singleSignOn.debug.sessionChangedId=SSO changing sessionID in session [{0}, oldSessionId {1}] from SSO session [{2}]
singleSignOn.debug.sessionLogout=SSO processing a log out for SSO session [{0}] and application session [{1}]
singleSignOn.debug.sessionTimeout=SSO processing a time out for SSO session [{0}] and application session [{1}]
singleSignOn.debug.update=SSO updating SSO session [{0}] to authentication type [{1}]
+singleSignOn.duplicateRealm=SSO found a realm defined on context [{0}], this will conflict with principals defined in the main realm
+singleSignOn.noRealm=This SSO [{0}] has no realm associated with it
singleSignOn.sessionExpire.contextNotFound=SSO unable to expire session [{0}] because the Context could not be found
singleSignOn.sessionExpire.engineNull=SSO unable to expire session [{0}] because the Engine was null
singleSignOn.sessionExpire.hostNotFound=SSO unable to expire session [{0}] because the Host could not be found
@@ -92,6 +95,6 @@
spnegoAuthenticator.ticketValidateFail=Failed to validate client supplied ticket
sslAuthenticatorValve.authFailed=Authentication with the provided certificates failed
-sslAuthenticatorValve.http2=The context [{0}] in virtual host [{1}] is configured to use CLIENT-CERT authentication and [{2}] is configured to support HTTP/2. Use of CLIENT-CERT authentication is not compatible with the use of HTTP/2.
+sslAuthenticatorValve.http2=The context [{0}] in virtual host [{1}] is configured to use CLIENT-CERT authentication and [{2}] is configured to support HTTP/2. Use of CLIENT-CERT authentication is not compatible with the use of HTTP/2 unless certificateVerification is set to required.
sslAuthenticatorValve.noCertificates=No certificates are included with this request
-sslAuthenticatorValve.tls13=The context [{0}] in virtual host [{1}] is configured to use CLIENT-CERT authentication and [{2}] is configured to support TLS 1.3 using JSSE. Use of CLIENT-CERT authentication is not compatible with the use of TLS 1.3 and JSSE.
+sslAuthenticatorValve.tls13=The context [{0}] in virtual host [{1}] is configured to use CLIENT-CERT authentication and [{2}] is configured to support TLS 1.3 using JSSE. Use of CLIENT-CERT authentication is not compatible with the use of TLS 1.3 and JSSE unless certificateVerification is set to required.
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings_fr.properties tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings_fr.properties
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings_fr.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings_fr.properties 2026-01-23 19:33:36.000000000 +0000
@@ -42,7 +42,7 @@
authenticator.userDataPermissionFail=Les données envoyées par l'utilisateur ne répondent pas aux contraintes définies pour la ressource
authenticator.userPermissionFail=L''utilisateur [{0}] n''a pas l''autorisation d''accéder à la ressource
-basicAuthenticator.invalidAuthorization=L''autorisation est invalide: [{0}]
+basicAuthenticator.invalidAuthorization=L'autorisation est invalide
basicAuthenticator.invalidCharset=Les seules valeurs permises sont null, la chaîne vide, ou des caractères UTF-8
basicAuthenticator.notBase64=Les informations d'identification Basic ne sont pas encodées en Base64
basicAuthenticator.notBasic=La méthode d'authentification n'est pas ''Basic''
@@ -76,9 +76,12 @@
singleSignOn.debug.principalNotFound=Le SSO n''a pas trouvé de principal en cache, le cookie SSO de la session [{0}] est effacé
singleSignOn.debug.register=Enregistrement de la session SSO [{0}] pour l''utilisateur [{1}] avec le type d''authentification [{2}]
singleSignOn.debug.removeSession=Le SSO retire la session applicative [{0}] de la session SSO [{1}]
+singleSignOn.debug.sessionChangedId=Changement de l''id de session [{0}, ancien id {1}] dans la session SSO [{2}]
singleSignOn.debug.sessionLogout=Le SSO effectue une déconnection pour la session SSO [{0}] et la session [{1}] de l''application
singleSignOn.debug.sessionTimeout=Le SSO traite un timeout pour la session SSO [{0}] et la session [{1}] de l''application
singleSignOn.debug.update=Le SSO met à jour la session SSO [{0}] avec le type d''authentification [{1}]
+singleSignOn.duplicateRealm=Le SSO a trouvé un royaume défini sur le contexte [{0}] qui va entrer en conflit avec les principals définis dans le royaume du SSO
+singleSignOn.noRealm=Ce SSO [{0}] n''a aucun royaume associé avec lui
singleSignOn.sessionExpire.contextNotFound=Le SSO n''a pu faire expirer la session [{0}] parce que le contexte n''a pas été trouvé
singleSignOn.sessionExpire.engineNull=Le SSO n''a pu faire expirer la session [{0}] parce que le moteur est null
singleSignOn.sessionExpire.hostNotFound=SSO ne peut pas faire expirer le session [{0}] parce que l''hôte ("Host") n''a pas été trouvé
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -42,7 +42,7 @@
authenticator.userDataPermissionFail=ユーザデータがリソースの制約に従っていません
authenticator.userPermissionFail=ユーザ [{0}] にはリソースへのアクセス権限がありません
-basicAuthenticator.invalidAuthorization=無効な認証: [{0}]
+basicAuthenticator.invalidAuthorization=無効な認証
basicAuthenticator.invalidCharset=指定できる値は、null、空の文字列またはUTF-8です。
basicAuthenticator.notBase64=Basic認証の資格情報がBase64ではありません
basicAuthenticator.notBasic=認証ヘッダメソッドが ''Basic'' ではありません
@@ -76,9 +76,12 @@
singleSignOn.debug.principalNotFound=SSO はキャッシュされたプリンシパルを検出しませんでした。セッション [{0}] の SSO Cookie を消去しています
singleSignOn.debug.register=SSO は認証タイプ [{2}] のユーザー [{1}] の SSO セッション [{0}] を登録しています
singleSignOn.debug.removeSession=SSOはSSOセッション [{1}] からアプリケーションセッション [{0}] を削除しています
+singleSignOn.debug.sessionChangedId=SSO は SSO セッション [{2}] からセッション [{0}、oldSessionId {1}] のセッション ID を変更しています
singleSignOn.debug.sessionLogout=SSOはSSOセッション[{0}]とアプリケーションセッション[{1}]をログアウト処理しています
singleSignOn.debug.sessionTimeout=SSOはSSOセッション[{0}]とアプリケーションセッション[{1}]のタイムアウトを処理しています
singleSignOn.debug.update=SSOはSSOセッション [{0}] を認証タイプ [{1}] に更新します
+singleSignOn.duplicateRealm=SSO はコンテキスト [{0}] で定義されたレルムを検出しました。これはメインレルムで定義されたプリンシパルと競合します
+singleSignOn.noRealm=このSSO [{0}]にはレルムが関連付けられていません
singleSignOn.sessionExpire.contextNotFound=Context が見つからないため、SSO はセッション [{0}] を破棄できません
singleSignOn.sessionExpire.engineNull=Engine が null だったため、SSO はセッション [{0}] を破棄できません
singleSignOn.sessionExpire.hostNotFound=ホストが見つからないため SSO セッション [{0}] を破棄できません
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -16,4 +16,7 @@
# Do not edit this file directly.
# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
+authenticator.check.found=Уже аутентифицирован [{0}]
authenticator.noAuthHeader=Заголовок авторизации не был отправлен клиентом
+
+basicAuthenticator.invalidCharset=Единственные разрешенные значения это null, пустая строка или UTF-8
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,8 +25,6 @@
/**
* An Authenticator and Valve implementation that checks only security constraints not involving user
* authentication.
- *
- * @author Craig R. McClanahan
*/
public final class NonLoginAuthenticator extends AuthenticatorBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SSLAuthenticator.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SSLAuthenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SSLAuthenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SSLAuthenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -37,12 +37,11 @@
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.Constants;
import org.apache.tomcat.util.net.SSLHostConfig;
+import org.apache.tomcat.util.net.SSLHostConfig.CertificateVerification;
/**
* An Authenticator and Valve implementation of authentication that utilizes SSL certificates to identify
* client users.
- *
- * @author Craig R. McClanahan
*/
public class SSLAuthenticator extends AuthenticatorBase {
@@ -60,14 +59,17 @@
@Override
protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
- // NOTE: We don't try to reauthenticate using any existing SSO session,
- // because that will only work if the original authentication was
- // BASIC or FORM, which are less secure than the CLIENT-CERT auth-type
- // specified for this webapp
- //
- // Change to true below to allow previous FORM or BASIC authentications
- // to authenticate users for this webapp
- // TODO make this a configurable attribute (in SingleSignOn??)
+ /*
+ * Reauthentication using the cached user name and password (if any) is not enabled for CLIENT-CERT
+ * authentication. This was an historical design decision made because CLIENT-CERT authentication is viewed as
+ * more secure than BASIC/FORM.
+ *
+ * However, reauthentication was introduced to handle the case where the Realm took additional actions on
+ * authentication. Reauthenticating with the cached user name and password may not be sufficient for CLIENT-CERT
+ * since it will not make any TLS information (client certificate etc) available that a web application may
+ * depend on. Therefore, the reauthentication behaviour for CLIENT-CERT is to perform a normal CLIENT-CERT
+ * authentication.
+ */
if (checkForCachedAuthentication(request, response, false)) {
return true;
}
@@ -175,28 +177,52 @@
Connector[] connectors = engine.getService().findConnectors();
for (Connector connector : connectors) {
- // First check for upgrade
- UpgradeProtocol[] upgradeProtocols = connector.findUpgradeProtocols();
- for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
- if ("h2".equals(upgradeProtocol.getAlpnName())) {
- log.warn(sm.getString("sslAuthenticatorValve.http2", context.getName(), host.getName(), connector));
+ /*
+ * There are two underlying issues here.
+ *
+ * 1. JSSE does not implement post-handshake authentication (PHA) for TLS 1.3. That means CLIENT-CERT
+ * authentication will only work if the virtual host requires a certificate OR the client never requests a
+ * protected resource.
+ *
+ * 2. HTTP/2 does not permit re-negotiation nor PHA. That means CLIENT-CERT authentication will only work if
+ * the virtual host requires a certificate OR the client never requests a protected resource.
+ *
+ * We can't rely on the client never requesting a protected resource but we can check if all the virtual
+ * hosts are configured to require a certificate.
+ */
+ boolean allHostsRequireCertificate = true;
+ for (SSLHostConfig sslHostConfig : connector.findSslHostConfigs()) {
+ if (sslHostConfig.getCertificateVerification() != CertificateVerification.REQUIRED) {
+ allHostsRequireCertificate = false;
break;
}
}
- // Then check for TLS 1.3
- SSLHostConfig[] sslHostConfigs = connector.findSslHostConfigs();
- for (SSLHostConfig sslHostConfig : sslHostConfigs) {
- if (!sslHostConfig.isTls13RenegotiationAvailable()) {
- String[] enabledProtocols = sslHostConfig.getEnabledProtocols();
- if (enabledProtocols == null) {
- // Possibly boundOnInit is used, so use the less accurate protocols
- enabledProtocols = sslHostConfig.getProtocols().toArray(new String[0]);
+ // Only need to check for use of HTTP/2 or TLS 1.3 if one or more hosts doesn't require a certificate
+ if (!allHostsRequireCertificate) {
+ // Check if the Connector is configured to support upgrade to HTTP/2
+ UpgradeProtocol[] upgradeProtocols = connector.findUpgradeProtocols();
+ for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
+ if ("h2".equals(upgradeProtocol.getAlpnName())) {
+ log.warn(sm.getString("sslAuthenticatorValve.http2", context.getName(), host.getName(),
+ connector));
+ break;
}
- for (String enabledProtocol : enabledProtocols) {
- if (Constants.SSL_PROTO_TLSv1_3.equals(enabledProtocol)) {
- log.warn(sm.getString("sslAuthenticatorValve.tls13", context.getName(), host.getName(),
- connector));
+ }
+
+ // Check if any of the virtual hosts support TLS 1.3 without supporting PHA
+ for (SSLHostConfig sslHostConfig : connector.findSslHostConfigs()) {
+ if (!sslHostConfig.isTls13RenegotiationAvailable()) {
+ String[] enabledProtocols = sslHostConfig.getEnabledProtocols();
+ if (enabledProtocols == null) {
+ // Possibly boundOnInit is used, so use the less accurate protocols
+ enabledProtocols = sslHostConfig.getProtocols().toArray(new String[0]);
+ }
+ for (String enabledProtocol : enabledProtocols) {
+ if (Constants.SSL_PROTO_TLSv1_3.equals(enabledProtocol)) {
+ log.warn(sm.getString("sslAuthenticatorValve.tls13", context.getName(), host.getName(),
+ connector));
+ }
}
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SavedRequest.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SavedRequest.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SavedRequest.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SavedRequest.java 2026-01-23 19:33:36.000000000 +0000
@@ -35,8 +35,6 @@
*
* IMPLEMENTATION NOTE - It is assumed that this object is accessed only from the context of a single thread, so
* no synchronization around internal collection classes is performed.
- *
- * @author Craig R. McClanahan
*/
public final class SavedRequest implements Serializable {
@@ -181,13 +179,26 @@
/**
* The original maxInactiveInterval for the session.
*/
- private int originalMaxInactiveInterval = -1;
+ private Integer originalMaxInactiveInterval = null;
- public int getOriginalMaxInactiveInterval() {
+ public Integer getOriginalMaxInactiveIntervalOptional() {
return originalMaxInactiveInterval;
}
+ /**
+ * Obtain the original session maxInactiveInterval.
+ *
+ * @return the original session maxInactiveInterval
+ *
+ * @deprecated This method will be removed in Tomcat 12.0.x onwards. Use
+ * {@link SavedRequest#getOriginalMaxInactiveIntervalOptional()}
+ */
+ @Deprecated
+ public int getOriginalMaxInactiveInterval() {
+ return (originalMaxInactiveInterval == null) ? -1 : originalMaxInactiveInterval.intValue();
+ }
+
public void setOriginalMaxInactiveInterval(int originalMaxInactiveInterval) {
- this.originalMaxInactiveInterval = originalMaxInactiveInterval;
+ this.originalMaxInactiveInterval = Integer.valueOf(originalMaxInactiveInterval);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOn.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOn.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOn.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOn.java 2026-01-23 19:33:36.000000000 +0000
@@ -28,6 +28,7 @@
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Manager;
import org.apache.catalina.Realm;
@@ -50,8 +51,33 @@
*
The web applications themselves must use one of the standard Authenticators found in the
* org.apache.catalina.authenticator package.
*
- *
- * @author Craig R. McClanahan
+ *
+ * On first authentication to any web application, an SSO session is created and the authenticated Principal, the
+ * authentication type and the plain text user name and password used to authenticate (if available) are cached using a
+ * key based on the SSO session. On subsequent requests to a web application on the Host where this Valve is configured,
+ * the cached authenticated Principal and the authentication type are added to the request by the SSO Valve and no
+ * further authentication takes place.
+ *
+ * In some scenarios, adding the authenticated Principal and the authentication type is insufficient. This usually
+ * occurs when the web application depends on additional actions the Realm takes on authentication which are bypassed by
+ * the SSO Valve. Examples of this include the Realm setting security credentials on the request thread to support EJB
+ * access or the CLIENT-CERT authenticator providing the client certificate and other TLS attributes. To address this,
+ * the {@code requireReauthentication} flag can be set to {@code true} which will cause the SSO Valve not to set the
+ * cached Principal and authentication type on the request and the web application authenticator will authenticate the
+ * request. By default this reauthentication will occur in the following ways:
+ *
+ *
BASIC - call the realm using the plain text user name and password cached by the SSO Valve if available. If not
+ * cached, obtain those values from the request. If not present in the request, request them from the user agent.
+ *
FORM - call the realm using the plain text user name and password cached by the SSO Valve if available. If not
+ * cached, request them from the user agent.
+ *
DIGEST - call the realm using the credentials present in the request. If not present in the request, request them
+ * from the user agent.
+ *
CLIENT-CERT - call the realm using the credentials present in the TLS connection. If not present in the TLS
+ * connection, request them from the user agent.
+ *
SPNEGO - request authentication credentials from the user agent.
+ *
+ * Note that this means that enabling reauthentication only makes sense if there are two or more web applications in the
+ * Host that use BASIC or FORM. If that is not the case, the SSO Valve will just add processing overhead.
*/
public class SingleSignOn extends ValveBase {
@@ -426,8 +452,8 @@
Session session;
try {
session = manager.findSession(key.getSessionId());
- } catch (IOException e) {
- containerLog.warn(sm.getString("singleSignOn.sessionExpire.managerError", key), e);
+ } catch (IOException ioe) {
+ containerLog.warn(sm.getString("singleSignOn.sessionExpire.managerError", key), ioe);
return;
}
if (session == null) {
@@ -439,8 +465,8 @@
/**
- * Attempts reauthentication to the given Realm using the credentials associated with the single
- * sign-on session identified by argument ssoId.
+ * Attempts reauthentication to the given Realm using the cached plain text credentials associated with
+ * the single sign-on session identified by argument ssoId.
*
* If reauthentication is successful, the Principal and authorization type associated with the SSO
* session will be bound to the given Request object via calls to {@link Request#setAuthType
@@ -480,6 +506,15 @@
}
+ protected void populateRequestFromSsoEntry(Request request, String ssoId) {
+ SingleSignOnEntry entry = cache.get(ssoId);
+ if (entry != null) {
+ request.setAuthType(entry.getAuthType());
+ request.setUserPrincipal(entry.getPrincipal());
+ }
+ }
+
+
/**
* Register the specified Principal as being associated with the specified value for the single sign on identifier.
*
@@ -571,12 +606,39 @@
@Override
protected void startInternal() throws LifecycleException {
- Container c = getContainer();
- while (c != null && !(c instanceof Engine)) {
- c = c.getParent();
- }
- if (c != null) {
- engine = (Engine) c;
+ Container container = getContainer();
+ while (container != null && !(container instanceof Engine)) {
+ container = container.getParent();
+ }
+ if (container != null) {
+ engine = (Engine) container;
+ }
+ // Starting with the associated container, verify it has a realm associated,
+ // and that no child container returns a different realm
+ container = getContainer();
+ Realm containerRealm = container.getRealm();
+ if (containerRealm == null) {
+ containerLog.warn(sm.getString("singleSignOn.noRealm", container.getName()));
+ } else {
+ if (container instanceof Engine) {
+ for (Container host : engine.findChildren()) {
+ if (host.getRealm() != containerRealm) {
+ containerLog.warn(sm.getString("singleSignOn.duplicateRealm", host.getName()));
+ } else {
+ for (Container context : host.findChildren()) {
+ if (context.getRealm() != containerRealm) {
+ containerLog.warn(sm.getString("singleSignOn.duplicateRealm", context.getName()));
+ }
+ }
+ }
+ }
+ } else if (container instanceof Host) {
+ for (Container context : container.findChildren()) {
+ if (context.getRealm() != containerRealm) {
+ containerLog.warn(sm.getString("singleSignOn.duplicateRealm", context.getName()));
+ }
+ }
+ }
}
super.startInternal();
}
@@ -587,4 +649,27 @@
super.stopInternal();
engine = null;
}
+
+ protected void sessionChangedId(String ssoId, Session session, String oldSessionId) {
+ if (containerLog.isDebugEnabled()) {
+ containerLog.debug(sm.getString("singleSignOn.debug.sessionChangedId", session, oldSessionId, ssoId));
+ }
+
+ SingleSignOnEntry entry = cache.get(ssoId);
+ if (entry == null) {
+ return;
+ }
+
+ /*
+ * Associate the new sessionId with this SingleSignOnEntry. A SessionListener will be registered for the new
+ * sessionID. If not, then we would not notice any subsequent Session.SESSION_DESTROYED_EVENT for the session.
+ */
+ entry.addSession(this, ssoId, session);
+
+ /*
+ * Remove the obsolete sessionId from the SingleSignOnEntry. The sessionId part of the SingleSignOnSessionKey is
+ * final.
+ */
+ entry.removeSession(session, oldSessionId);
+ }
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOnEntry.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOnEntry.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOnEntry.java 2026-01-23 19:33:36.000000000 +0000
@@ -34,8 +34,6 @@
* AuthenticatorBase subclasses that need it in order to perform reauthentications when SingleSignOn is in
* use.
*
- * @author B Stansberry, based on work by Craig R. McClanahan
- *
* @see SingleSignOn
* @see AuthenticatorBase#reauthenticateFromSSO
*/
@@ -101,6 +99,18 @@
sessionKeys.remove(key);
}
+ /**
+ * Removes the given Session from the list of those associated with this SSO, using the previous
+ * sessionId
+ *
+ * @param session the Session to remove.
+ * @param oldSessionId the previous sessionId of the Session to remove.
+ */
+ public void removeSession(Session session, String oldSessionId) {
+ SingleSignOnSessionKey key = new SingleSignOnSessionKey(session, oldSessionId);
+ sessionKeys.remove(key);
+ }
+
/**
* Returns the HTTP Session identifiers associated with this SSO.
*
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOnListener.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOnListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOnListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOnListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -38,7 +38,8 @@
@Override
public void sessionEvent(SessionEvent event) {
- if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())) {
+ final String type = event.getType();
+ if (!(Session.SESSION_DESTROYED_EVENT.equals(type) || Session.SESSION_CHANGED_ID_EVENT.equals(type))) {
return;
}
@@ -56,6 +57,15 @@
if (sso == null) {
return;
}
- sso.sessionDestroyed(ssoId, session);
+
+ switch (type) {
+ case Session.SESSION_CHANGED_ID_EVENT:
+ sso.sessionChangedId(ssoId, session, (String) event.getData());
+ break;
+
+ case Session.SESSION_DESTROYED_EVENT:
+ sso.sessionDestroyed(ssoId, session);
+ break;
+ }
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java 2026-01-23 19:33:36.000000000 +0000
@@ -41,6 +41,13 @@
this.hostName = context.getParent().getName();
}
+ public SingleSignOnSessionKey(Session session, String sessionId) {
+ this.sessionId = sessionId;
+ Context context = session.getManager().getContext();
+ this.contextName = context.getName();
+ this.hostName = context.getParent().getName();
+ }
+
public String getSessionId() {
return sessionId;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java 2026-01-23 19:33:36.000000000 +0000
@@ -135,7 +135,17 @@
@Override
protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
- if (checkForCachedAuthentication(request, response, true)) {
+ /*
+ * Reauthentication using the cached user name and password (if any) is not enabled for SPNEGO authentication.
+ * This is because the delegated credentials will nto be available unless a normal SPNEGO authentication takes
+ * place.
+ *
+ * Reauthentication was introduced to handle the case where the Realm took additional actions on authentication.
+ * Reauthenticating with the cached user name and password may not be sufficient for SPNEGO since it will not
+ * make the delegated credentials available that a web application may depend on. Therefore, the
+ * reauthentication behaviour for SPNEGO is to perform a normal SPNEGO authentication.
+ */
+ if (checkForCachedAuthentication(request, response, false)) {
return true;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/jaspic/AuthConfigFactoryImpl.java 2026-01-23 19:33:36.000000000 +0000
@@ -556,7 +556,7 @@
@Override
public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject)
- throws AuthException {
+ throws AuthException {
return module.validateRequest(messageInfo, clientSubject, serviceSubject);
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/jaspic/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/authenticator/jaspic/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/jaspic/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/jaspic/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -18,4 +18,6 @@
authConfigFactoryImpl.zeroLengthAppContext=Название контекста приложения нулевой длины является недействительным
+persistentProviderRegistrations.deleteFail=Временный файл [{0}] не может быть удален
persistentProviderRegistrations.existsDeleteFail=Временный файл [{0}] уже существует и не может быть удалён
+persistentProviderRegistrations.moveFail=Невозможно переместить [{0}] в [{1}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java tomcat10-10.1.52/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
--- tomcat10-10.1.40/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java 2026-01-23 19:33:36.000000000 +0000
@@ -141,12 +141,12 @@
writer.write(" \n");
}
writer.write("\n");
- } catch (IOException e) {
+ } catch (IOException ioe) {
if (!configFileNew.delete()) {
Log log = LogFactory.getLog(PersistentProviderRegistrations.class);
log.warn(sm.getString("persistentProviderRegistrations.deleteFail", configFileNew.getAbsolutePath()));
}
- throw new SecurityException(e);
+ throw new SecurityException(ioe);
}
// Move the current file out of the way
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/ClientAbortException.java tomcat10-10.1.52/java/org/apache/catalina/connector/ClientAbortException.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/ClientAbortException.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/ClientAbortException.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
/**
* Extend IOException to identify it as being caused by an abort of a request by a remote client.
- *
- * @author Glenn L. Nielsen
*/
public final class ClientAbortException extends BadRequestException {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/Connector.java tomcat10-10.1.52/java/org/apache/catalina/connector/Connector.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/Connector.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/Connector.java 2026-01-23 19:33:36.000000000 +0000
@@ -29,22 +29,22 @@
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Service;
-import org.apache.catalina.core.AprStatus;
import org.apache.catalina.util.LifecycleMBeanBase;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.Adapter;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.UpgradeProtocol;
import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
-import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.jni.AprStatus;
import org.apache.tomcat.util.IntrospectionUtils;
import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.buf.CharsetUtil;
import org.apache.tomcat.util.buf.EncodedSolidusHandling;
import org.apache.tomcat.util.buf.StringUtils;
import org.apache.tomcat.util.compat.JreCompat;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.openssl.OpenSSLImplementation;
import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
@@ -53,9 +53,6 @@
/**
* Implementation of a Coyote connector.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class Connector extends LifecycleMBeanBase {
@@ -64,6 +61,22 @@
public static final String INTERNAL_EXECUTOR_NAME = "Internal";
+ private static final boolean aprStatusPresent;
+
+ static {
+ /*
+ * The AprStatus class has to be in the org.apache.tomcat.jni package so it can be referenced by the OpenSSL
+ * clean-up code to avoid a race condition on shutdown between the AprLifecycleListener shutting down the Tomcat
+ * Native library along with any remaining open connections and the OpenSSL clean-up code shutting down an
+ * individual connection that can trigger a JVM crash.
+ *
+ * In some deployment scenarios AprStatus is not present - e.g. because tomcat-jni.jar is not present. To avoid
+ * a CNFE in this class on Connector initialisation when AprStatus is not present - and ugly work-arounds that
+ * try loading the class and catching the exception - use getResource() to see if AprStatus is present.
+ */
+ aprStatusPresent =
+ (Connector.class.getClassLoader().getResource("org/apache/tomcat/jni/AprStatus.class") != null);
+ }
// ------------------------------------------------------------ Constructor
@@ -212,6 +225,10 @@
*/
protected int maxParameterCount = 10000;
+ private int maxPartCount = 50;
+
+ private int maxPartHeaderSize = 512;
+
/**
* Maximum size of a POST which will be automatically parsed by the container. 2 MiB by default.
*/
@@ -227,7 +244,7 @@
* Comma-separated list of HTTP methods that will be parsed according to POST-style rules for
* application/x-www-form-urlencoded request bodies.
*/
- protected String parseBodyMethods = "POST";
+ protected String parseBodyMethods = Method.POST;
/**
* A Set of methods determined by {@link #parseBodyMethods}.
@@ -482,6 +499,26 @@
}
+ public int getMaxPartCount() {
+ return maxPartCount;
+ }
+
+
+ public void setMaxPartCount(int maxPartCount) {
+ this.maxPartCount = maxPartCount;
+ }
+
+
+ public int getMaxPartHeaderSize() {
+ return maxPartHeaderSize;
+ }
+
+
+ public void setMaxPartHeaderSize(int maxPartHeaderSize) {
+ this.maxPartHeaderSize = maxPartHeaderSize;
+ }
+
+
/**
* @return the maximum size of a POST which will be automatically parsed by the container.
*/
@@ -541,7 +578,7 @@
methodSet.addAll(Arrays.asList(StringUtils.splitCommaSeparated(methods)));
}
- if (methodSet.contains("TRACE")) {
+ if (methodSet.contains(Method.TRACE)) {
throw new IllegalArgumentException(sm.getString("coyoteConnector.parseBodyMethodNoTrace"));
}
@@ -1025,25 +1062,21 @@
setParseBodyMethods(getParseBodyMethods());
}
- if (JreCompat.isJre22Available() && OpenSSLStatus.getUseOpenSSL() && OpenSSLStatus.isAvailable() &&
- protocolHandler instanceof AbstractHttp11Protocol) {
- // Use FFM and OpenSSL if available
- AbstractHttp11JsseProtocol> jsseProtocolHandler = (AbstractHttp11JsseProtocol>) protocolHandler;
- if (jsseProtocolHandler.isSSLEnabled() && jsseProtocolHandler.getSslImplementationName() == null) {
- // OpenSSL is compatible with the JSSE configuration, so use it if it is available
- jsseProtocolHandler
- .setSslImplementationName("org.apache.tomcat.util.net.openssl.panama.OpenSSLImplementation");
- }
- } else if (AprStatus.isAprAvailable() && AprStatus.getUseOpenSSL() &&
- protocolHandler instanceof AbstractHttp11Protocol) {
- // Use tomcat-native and OpenSSL otherwise, if available
+ if (protocolHandler instanceof AbstractHttp11JsseProtocol) {
AbstractHttp11JsseProtocol> jsseProtocolHandler = (AbstractHttp11JsseProtocol>) protocolHandler;
if (jsseProtocolHandler.isSSLEnabled() && jsseProtocolHandler.getSslImplementationName() == null) {
- // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
- jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
+ // If SSL is enabled and a specific implementation isn't specified, select the correct default.
+ if (JreCompat.isJre22Available() && OpenSSLStatus.getUseOpenSSL() && OpenSSLStatus.isAvailable()) {
+ // Use FFM and OpenSSL if available
+ jsseProtocolHandler.setSslImplementationName(
+ "org.apache.tomcat.util.net.openssl.panama.OpenSSLImplementation");
+ } else if (aprStatusPresent && AprStatus.isAprAvailable() && AprStatus.getUseOpenSSL()) {
+ // Use tomcat-native and OpenSSL otherwise, if available
+ jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
+ }
+ // Otherwise the default JSSE will be used
}
}
- // Otherwise the default JSSE will be used
try {
protocolHandler.init();
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteAdapter.java tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteAdapter.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteAdapter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteAdapter.java 2026-01-23 19:33:36.000000000 +0000
@@ -48,6 +48,7 @@
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.http.ServerCookie;
import org.apache.tomcat.util.http.ServerCookies;
import org.apache.tomcat.util.net.SSLSupport;
@@ -57,9 +58,6 @@
/**
* Implementation of a request processor which delegates the processing to a Coyote processor.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class CoyoteAdapter implements Adapter {
@@ -260,9 +258,9 @@
}
success = false;
}
- } catch (IOException e) {
+ } catch (IOException ioe) {
+ // Issues that should be logged will have already been logged
success = false;
- // Ignore
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
success = false;
@@ -373,8 +371,8 @@
response.finishResponse();
}
- } catch (IOException e) {
- // Ignore
+ } catch (IOException ignore) {
+ // Issues that should be logged will have already been logged
} finally {
AtomicBoolean error = new AtomicBoolean(false);
res.action(ActionCode.IS_ERROR, error);
@@ -595,7 +593,7 @@
// Check for ping OPTIONS * request
if (undecodedURI.equals("*")) {
- if (req.method().equals("OPTIONS")) {
+ if (Method.OPTIONS.equals(req.getMethod())) {
StringBuilder allow = new StringBuilder();
allow.append("GET, HEAD, POST, PUT, DELETE, OPTIONS");
// Trace if allowed
@@ -614,7 +612,7 @@
MessageBytes decodedURI = req.decodedURI();
// Filter CONNECT method
- if (req.method().equals("CONNECT")) {
+ if (Method.CONNECT.equals(req.getMethod())) {
response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, sm.getString("coyoteAdapter.connect"));
} else {
// No URI for CONNECT requests
@@ -782,8 +780,8 @@
// point.
try {
Thread.sleep(1000);
- } catch (InterruptedException e) {
- // Should never happen
+ } catch (InterruptedException ignore) {
+ // Should never happen but, if it does, just continue looping
}
// Reset mapping
request.getMappingData().recycle();
@@ -813,14 +811,14 @@
}
// Filter TRACE method
- if (!connector.getAllowTrace() && req.method().equals("TRACE")) {
+ if (!connector.getAllowTrace() && Method.TRACE.equals(req.getMethod())) {
Wrapper wrapper = request.getWrapper();
StringBuilder header = null;
if (wrapper != null) {
String[] methods = wrapper.getServletMethods();
if (methods != null) {
for (String method : methods) {
- if ("TRACE".equals(method)) {
+ if (Method.TRACE.equals(method)) {
continue;
}
if (header == null) {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteInputStream.java tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteInputStream.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteInputStream.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteInputStream.java 2026-01-23 19:33:36.000000000 +0000
@@ -31,8 +31,6 @@
/**
* This class handles reading bytes.
- *
- * @author Remy Maucherat
*/
public class CoyoteInputStream extends ServletInputStream {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteOutputStream.java tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteOutputStream.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteOutputStream.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteOutputStream.java 2026-01-23 19:33:36.000000000 +0000
@@ -27,9 +27,6 @@
/**
* Coyote implementation of the servlet output stream.
- *
- * @author Costin Manolache
- * @author Remy Maucherat
*/
public class CoyoteOutputStream extends ServletOutputStream {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/CoyotePrincipal.java tomcat10-10.1.52/java/org/apache/catalina/connector/CoyotePrincipal.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/CoyotePrincipal.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/CoyotePrincipal.java 2026-01-23 19:33:36.000000000 +0000
@@ -22,8 +22,6 @@
/**
* Generic implementation of java.security.Principal that is used to represent principals authenticated
* at the protocol handler level.
- *
- * @author Remy Maucherat
*/
public class CoyotePrincipal implements Principal, Serializable {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteReader.java tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteReader.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteReader.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteReader.java 2026-01-23 19:33:36.000000000 +0000
@@ -22,8 +22,6 @@
/**
* Coyote implementation of the buffered reader.
- *
- * @author Remy Maucherat
*/
public class CoyoteReader extends BufferedReader {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteWriter.java tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteWriter.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/CoyoteWriter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/CoyoteWriter.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,8 +21,6 @@
/**
* Coyote implementation of the servlet writer.
- *
- * @author Remy Maucherat
*/
public class CoyoteWriter extends PrintWriter {
@@ -91,8 +89,8 @@
try {
ob.flush();
- } catch (IOException e) {
- setErrorException(e);
+ } catch (IOException ioe) {
+ setErrorException(ioe);
}
}
@@ -105,7 +103,7 @@
// so the stream can be reused. We close ob.
try {
ob.close();
- } catch (IOException ex) {
+ } catch (IOException ignore) {
// Ignore
}
error = false;
@@ -129,8 +127,8 @@
try {
ob.write(c);
- } catch (IOException e) {
- setErrorException(e);
+ } catch (IOException ioe) {
+ setErrorException(ioe);
}
}
@@ -145,8 +143,8 @@
try {
ob.write(buf, off, len);
- } catch (IOException e) {
- setErrorException(e);
+ } catch (IOException ioe) {
+ setErrorException(ioe);
}
}
@@ -167,8 +165,8 @@
try {
ob.write(s, off, len);
- } catch (IOException e) {
- setErrorException(e);
+ } catch (IOException ioe) {
+ setErrorException(ioe);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/InputBuffer.java tomcat10-10.1.52/java/org/apache/catalina/connector/InputBuffer.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/InputBuffer.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/InputBuffer.java 2026-01-23 19:33:36.000000000 +0000
@@ -48,8 +48,6 @@
* The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3 OutputBuffer, adapted to handle input
* instead of output. This allows complete recycling of the facade objects (the ServletInputStream and the
* BufferedReader).
- *
- * @author Remy Maucherat
*/
public class InputBuffer extends Reader implements ByteChunk.ByteInputChannel, ApplicationBufferHandler {
@@ -60,6 +58,8 @@
private static final Log log = LogFactory.getLog(InputBuffer.class);
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
+
public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
// The buffer can be used for byte[] and char[] reading
@@ -76,8 +76,11 @@
// ----------------------------------------------------- Instance Variables
- /**
- * The byte buffer.
+ /*
+ * The byte buffer. Data is always injected into this class by calling {@link #setByteBuffer(ByteBuffer)} rather
+ * than copying data into any existing buffer. It is initialised to an empty buffer as there are code paths that
+ * access the buffer when it is expected to be empty and an empty buffer gives cleaner code than lots of null
+ * checks.
*/
private ByteBuffer bb;
@@ -151,8 +154,8 @@
public InputBuffer(int size) {
this.size = size;
- bb = ByteBuffer.allocate(size);
- clear(bb);
+ // Will be replaced when there is data to read so initialise to empty buffer.
+ bb = EMPTY_BUFFER;
cb = CharBuffer.allocate(size);
clear(cb);
readLimit = size;
@@ -191,7 +194,11 @@
}
readLimit = size;
markPos = -1;
- clear(bb);
+ /*
+ * This buffer will have been replaced if there was data to read so re-initialise to an empty buffer to clear
+ * any reference to an injected buffer.
+ */
+ bb = EMPTY_BUFFER;
closed = false;
if (conv != null) {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings.properties tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -62,6 +62,7 @@
coyoteRequest.noAsync=Unable to start async because the following classes in the processing chain do not support async [{0}]
coyoteRequest.noMultipartConfig=Unable to process parts as no multi-part configuration has been provided
coyoteRequest.parseParameters=Exception thrown whilst processing POSTed parameters
+coyoteRequest.partsParseException=Exception [{0}] occurred parsing parts and will be thrown
coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
coyoteRequest.sendfileNotCanonical=Unable to determine canonical name of file [{0}] specified for use with sendfile
coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed
@@ -91,6 +92,7 @@
request.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed
request.illegalWrap=The request wrapper must wrap the request obtained from getRequest()
request.notAsync=It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
+request.partCleanup.failed=Unable to delete temporary file for uploaded part after multi-part processing failed
request.session.failed=Failed to load session [{0}] due to [{1}]
requestFacade.nullRequest=The request object has been recycled and is no longer associated with this facade
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_es.properties tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_es.properties
--- tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_es.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_es.properties 2026-01-23 19:33:36.000000000 +0000
@@ -38,7 +38,7 @@
coyoteRequest.attributeEvent=Excepción lanzada mediante el escuchador de eventos de atributos
coyoteRequest.authenticate.ise=No puedo llamar a authenticate() tras haberse acometido la respuesta
coyoteRequest.changeSessionId=No se puede cambiar el ID de sesión. No hay sesión asociada con esta solicitud
-coyoteRequest.chunkedPostTooLarge=No se han analizado los parámetros porque la medida de los datos enviados meiante "post" era demasiado grande. Debido a que este requerimiento es una parte del original, no puede ser procesado. Utiliza el atributo "maxPostSize" del conector para resolver esta situación, en caso de que la aplicación deba de aceptar POSTs mayores.
+coyoteRequest.chunkedPostTooLarge=No se han analizado los parámetros porque la medida de los datos enviados meiante POST era demasiado grande. Debido a que este requerimiento es una parte del original, no puede ser procesado. Utiliza el atributo "maxPostSize" del conector para resolver esta situación, en caso de que la aplicación deba de aceptar POSTs mayores.
coyoteRequest.filterAsyncSupportUnknown=Imposible determinar si algún filtro no soporta procesamiento asincrónico
coyoteRequest.getInputStream.ise=getReader() ya ha sido llamado para este requerimiento
coyoteRequest.getReader.ise=getInputStream() ya ha sido llamado para este requerimiento
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_fr.properties tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_fr.properties
--- tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_fr.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_fr.properties 2026-01-23 19:33:36.000000000 +0000
@@ -62,6 +62,7 @@
coyoteRequest.noAsync=Impossible de démarrer le mode asynchrone car les classes [{0}] de la chaîne de traitement ne le supportent pas
coyoteRequest.noMultipartConfig=Impossible de traiter des parties, parce qu'aucune configuration multi-parties n'a été fournie
coyoteRequest.parseParameters=Exception lors du traitement des paramètres envoyés par POST
+coyoteRequest.partsParseException=Une exception [{0}] s''est produite lors du traitement des portions du message et sera lancée
coyoteRequest.postTooLarge=Les paramètres n'ont pas été évalués car la taille des données postées est trop important. Utilisez l'attribut maxPostSize du connecteur pour corriger ce problème si votre application doit accepter des POSTs importants.
coyoteRequest.sendfileNotCanonical=Impossible d''obtenir le nom canonique du fichier [{0}] qui a été donné pour le sendfile
coyoteRequest.sessionCreateCommitted=Impossible de créer une session après que la réponse ait été envoyée
@@ -91,6 +92,7 @@
request.fragmentInDispatchPath=Le fragment dans le chemin de dispatch [{0}] a été enlevé
request.illegalWrap=L'enrobeur de la réponse doit enrober la requête obtenue à partir de getRequest()
request.notAsync=Il est interdit d'appeler cette méthode si la requête actuelle n'est pas en mode asynchrone (isAsyncStarted() a renvoyé false)
+request.partCleanup.failed=Impossible d'effacer le fichier temporaire pour la partie envoyée après l'échec de traitement du multi partie
request.session.failed=Erreur de chargement de la session [{0}] à cause de [{1}]
requestFacade.nullRequest=L'objet requête a été recyclé et n'est plus associé à cette façade
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -62,8 +62,9 @@
coyoteRequest.noAsync=処理チェーン内の次のクラスが非同期をサポートしていないため、非同期を開始できません [{0}]
coyoteRequest.noMultipartConfig=multi-part 構成が提供されていないため、partを処理できません
coyoteRequest.parseParameters=POST パラメーターの処理中に例外を投げました。
+coyoteRequest.partsParseException=パートの解析中に例外 [{0}] が発生しました
coyoteRequest.postTooLarge=POSTされたデータが大きすぎたので、パラメータが構文解析できませんでした。そのアプリケーションが巨大なPOSTを受け付けねばならない場合には、これを解決するためにコネクタのmaxPostSize属性を使用してください。
-coyoteRequest.sendfileNotCanonical=sendfile に指定されたファイル [{0}] の正式名を取得できません
+coyoteRequest.sendfileNotCanonical=sendfile に指定されたファイル [{0}] の正規名を取得できません
coyoteRequest.sessionCreateCommitted=レスポンスをコミットした後でセッションを作成できません
coyoteRequest.sessionEndAccessFail=リクエストの再利用中に行ったセッションへのアクセス終了処理で例外が送出されました。
coyoteRequest.setAttribute.namenull=setAttributeを名前を指定せずに呼び出すことはできません
@@ -91,6 +92,7 @@
request.fragmentInDispatchPath=ディスパッチパス [{0}] 中のフラグメントは除去されました
request.illegalWrap=リクエストラッパーは getRequest() で取得したリクエストをラップしなければなりません。
request.notAsync=非同期モードではないリクエストでこのメソッドを呼び出すことはできません。(例えば isAsyncStarted() が false を返す場合)
+request.partCleanup.failed=マルチパート処理が失敗した後、アップロードされたパートのテンポラリファイルを削除できませんでした
request.session.failed=[{1}]が原因で、セッション[{0}]の読み込みに失敗しました
requestFacade.nullRequest=リクエストオブジェクトは回収されこのファサードに関連付けられなくなりました。
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/connector/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -25,5 +25,6 @@
coyoteInputStream.nbNotready=В неблокирующем режиме невозможно читать из ServletInputStream до тех пор пока не завершится предыдущее чтение и IsReady() не вернёт true
+coyoteRequest.changeSessionId=Невозможно изменить ID сессии. Нет сессии связаной с этим запросом.
coyoteRequest.sendfileNotCanonical=Невозможно определить каноническое имя файла [{0}] указанное для использования с sendfile
coyoteRequest.sessionEndAccessFail=Исключение вызвало прекращение доступа к сессии при очистке запроса
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/OutputBuffer.java tomcat10-10.1.52/java/org/apache/catalina/connector/OutputBuffer.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/OutputBuffer.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/OutputBuffer.java 2026-01-23 19:33:36.000000000 +0000
@@ -37,14 +37,12 @@
import org.apache.coyote.Response;
import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.res.StringManager;
/**
* The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3 OutputBuffer, with the removal of some of
* the state handling (which in Coyote is mostly the Processor's responsibility).
- *
- * @author Costin Manolache
- * @author Remy Maucherat
*/
public class OutputBuffer extends Writer {
@@ -238,8 +236,8 @@
// - the content length has not been explicitly set
// AND
// - some content has been written OR this is NOT a HEAD request
- if ((!coyoteResponse.isCommitted()) && (coyoteResponse.getContentLengthLong() == -1) &&
- ((bb.remaining() > 0 || !coyoteResponse.getRequest().method().equals("HEAD")))) {
+ if (!coyoteResponse.isCommitted() && coyoteResponse.getContentLengthLong() == -1 &&
+ (bb.remaining() > 0 || !Method.HEAD.equals(coyoteResponse.getRequest().getMethod()))) {
coyoteResponse.setContentLength(bb.remaining());
}
@@ -335,11 +333,11 @@
// Prevent further output for this response
closed = true;
throw e;
- } catch (IOException e) {
+ } catch (IOException ioe) {
// An IOException on a write is almost always due to
// the remote client aborting the request. Wrap this
// so that it can be handled better by the error dispatcher.
- throw new ClientAbortException(e);
+ throw new ClientAbortException(ioe);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/Request.java tomcat10-10.1.52/java/org/apache/catalina/connector/Request.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/Request.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/Request.java 2026-01-23 19:33:36.000000000 +0000
@@ -111,6 +111,7 @@
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUpload;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
+import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException;
import org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException;
import org.apache.tomcat.util.http.fileupload.impl.SizeException;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
@@ -124,9 +125,6 @@
/**
* Wrapper object for the Coyote request.
- *
- * @author Remy Maucherat
- * @author Craig R. McClanahan
*/
public class Request implements HttpServletRequest {
@@ -143,6 +141,11 @@
*/
public Request(Connector connector) {
this.connector = connector;
+ if (connector != null) {
+ maxParameterCount = connector.getMaxParameterCount();
+ maxPartCount = connector.getMaxPartCount();
+ maxPartHeaderSize = connector.getMaxPartHeaderSize();
+ }
}
@@ -411,14 +414,22 @@
private HttpServletRequest applicationRequest = null;
+ /**
+ * The maximum number of request parameters
+ */
+ private int maxParameterCount = -1;
+
+ private int maxPartCount = -1;
+
+ private int maxPartHeaderSize = -1;
// --------------------------------------------------------- Public Methods
- protected void addPathParameter(String name, String value) {
+ public void addPathParameter(String name, String value) {
coyoteRequest.addPathParameter(name, value);
}
- protected String getPathParameter(String name) {
+ public String getPathParameter(String name) {
return coyoteRequest.getPathParameter(name);
}
@@ -441,6 +452,15 @@
userPrincipal = null;
subject = null;
parametersParsed = false;
+ if (connector != null) {
+ maxParameterCount = connector.getMaxParameterCount();
+ maxPartCount = connector.getMaxPartCount();
+ maxPartHeaderSize = connector.getMaxPartHeaderSize();
+ } else {
+ maxParameterCount = -1;
+ maxPartCount = -1;
+ maxPartHeaderSize = -1;
+ }
if (parts != null) {
for (Part part : parts) {
try {
@@ -505,7 +525,7 @@
}
- protected void recycleSessionInfo() {
+ public void recycleSessionInfo() {
if (session != null) {
try {
session.endAccess();
@@ -829,6 +849,36 @@
}
+ /**
+ * Set the maximum number of request parameters (GET plus POST including multipart) for a single request.
+ *
+ * @param maxParameterCount The maximum number of request parameters
+ */
+ public void setMaxParameterCount(int maxParameterCount) {
+ this.maxParameterCount = maxParameterCount;
+ }
+
+
+ /**
+ * Set the maximum number of parts for a single multipart request.
+ *
+ * @param maxPartCount The maximum number of request parts
+ */
+ public void setMaxPartCount(int maxPartCount) {
+ this.maxPartCount = maxPartCount;
+ }
+
+
+ /**
+ * Set the maximum header size per part for a single multipart request.
+ *
+ * @param maxPartHeaderSize The maximum size of the headers for one part
+ */
+ public void setMaxPartHeaderSize(int maxPartHeaderSize) {
+ this.maxPartHeaderSize = maxPartHeaderSize;
+ }
+
+
// ------------------------------------------------- ServletRequest Methods
@Override
@@ -900,8 +950,8 @@
* {@inheritDoc}
*
* The attribute names returned will only be those for the attributes set via {@link #setAttribute(String, Object)}.
- * Tomcat internal attributes will not be included even though they are accessible via {@link #getAttribute(String)}.
- * The Tomcat internal attributes include:
+ * Tomcat internal attributes will not be included even though they are accessible via
+ * {@link #getAttribute(String)}. The Tomcat internal attributes include:
*
*
{@link Globals#DISPATCHER_TYPE_ATTR}
*
{@link Globals#DISPATCHER_REQUEST_PATH_ATTR}
@@ -1381,8 +1431,8 @@
String canonicalPath;
try {
canonicalPath = new File(value.toString()).getCanonicalPath();
- } catch (IOException e) {
- throw new SecurityException(sm.getString("coyoteRequest.sendfileNotCanonical", value), e);
+ } catch (IOException ioe) {
+ throw new SecurityException(sm.getString("coyoteRequest.sendfileNotCanonical", value), ioe);
}
// Sendfile is performed in Tomcat's security context so need to
// check if the web app is permitted to access the file while still
@@ -2110,7 +2160,7 @@
@Override
public String getMethod() {
- return coyoteRequest.method().toStringType();
+ return coyoteRequest.getMethod();
}
@@ -2252,8 +2302,8 @@
Session session = null;
try {
session = manager.findSession(requestedSessionId);
- } catch (IOException e) {
- // Can't find the session
+ } catch (IOException ignore) {
+ // Error looking up session. Treat it as not found.
}
if ((session == null) || !session.isValid()) {
@@ -2265,8 +2315,8 @@
if (ctxt.getManager().findSession(requestedSessionId) != null) {
return true;
}
- } catch (IOException e) {
- // Ignore
+ } catch (IOException ignore) {
+ // Error looking up session. Treat it as not found.
}
}
}
@@ -2484,6 +2534,11 @@
parseParts(true);
if (partsParseException != null) {
+ Context context = getContext();
+ if (context != null && context.getLogger().isDebugEnabled()) {
+ context.getLogger()
+ .debug(sm.getString("coyoteRequest.partsParseException", partsParseException.getMessage()));
+ }
if (partsParseException instanceof IOException) {
throw (IOException) partsParseException;
} else if (partsParseException instanceof IllegalStateException) {
@@ -2514,15 +2569,33 @@
} else {
if (explicit) {
partsParseException = new IllegalStateException(sm.getString("coyoteRequest.noMultipartConfig"));
- return;
} else {
parts = Collections.emptyList();
- return;
}
+ return;
}
}
- int maxParameterCount = getConnector().getMaxParameterCount();
+ /*
+ * When the request body is multipart/form-data, both the parts and the query string count towards
+ * maxParameterCount. If parseParts() is called before getParameterXXX() then the parts will be parsed before
+ * the query string. Otherwise, the query string will be parsed first.
+ *
+ * maxParameterCount must be respected regardless of which is parsed first.
+ *
+ * maxParameterCount is reset from the Connector at the start of every request.
+ *
+ * If parts are parsed first, non-file parts will be added to the parameter map and any files will reduce
+ * maxParameterCount by 1 so that when the query string is parsed the difference between the size of the
+ * parameter map and maxParameterCount will be the original maxParameterCount less the number of parts. i.e. the
+ * maxParameterCount applied to the query string will be the original maxParameterCount less the number of
+ * parts.
+ *
+ * If the query string is parsed first, all parameters will be added to the parameter map and, ignoring
+ * maxPartCount, the part limit will be set to the original maxParameterCount less the size of the parameter
+ * map. i.e. the maxParameterCount applied to the parts will be the original maxParameterCount less the number
+ * of query parameters.
+ */
Parameters parameters = coyoteRequest.getParameters();
parameters.setLimit(maxParameterCount);
@@ -2571,35 +2644,53 @@
upload.setFileItemFactory(factory);
upload.setFileSizeMax(mce.getMaxFileSize());
upload.setSizeMax(mce.getMaxRequestSize());
- if (maxParameterCount > -1) {
- // There is a limit. The limit for parts needs to be reduced by
- // the number of parameters we have already parsed.
- // Must be under the limit else parsing parameters would have
- // triggered an exception.
- upload.setFileCountMax(maxParameterCount - parameters.size());
+ upload.setPartHeaderSizeMax(maxPartHeaderSize);
+ /*
+ * There are two independent limits on the number of parts.
+ *
+ * 1. The limit based on parameters. This is maxParameterCount less the number of parameters already
+ * processed.
+ *
+ * 2. The limit based on parts. This is maxPartCount.
+ *
+ * The lower of these two limits will be applied to this request.
+ *
+ * Note: Either of both limits may be set to -1 (unlimited).
+ */
+ int partLimit = maxParameterCount;
+ if (partLimit > -1) {
+ partLimit = partLimit - parameters.size();
+ }
+ int maxPartCount = this.maxPartCount;
+ if (maxPartCount > -1) {
+ if (partLimit < 0 || partLimit > maxPartCount) {
+ partLimit = maxPartCount;
+ }
}
+ upload.setFileCountMax(partLimit);
parts = new ArrayList<>();
+ List items = null;
try {
- List items = upload.parseRequest(new ServletRequestContext(this));
+ items = upload.parseRequest(new ServletRequestContext(this));
int maxPostSize = getConnector().getMaxPostSize();
- int postSize = 0;
+ long postSize = 0;
Charset charset = getCharset();
for (FileItem item : items) {
ApplicationPart part = new ApplicationPart(item, location);
- parts.add(part);
if (part.getSubmittedFileName() == null) {
String name = part.getName();
if (maxPostSize >= 0) {
// Have to calculate equivalent size. Not completely
// accurate but close enough.
- postSize += name.getBytes(charset).length;
+ // Name
+ postSize = Math.addExact(postSize, name.getBytes(charset).length);
// Equals sign
- postSize++;
+ postSize = Math.addExact(postSize, 1);
// Value length
- postSize += part.getSize();
+ postSize = Math.addExact(postSize, part.getSize());
// Value separator
- postSize++;
+ postSize = Math.addExact(postSize, 1);
if (postSize > maxPostSize) {
parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
throw new IllegalStateException(sm.getString("coyoteRequest.maxPostSizeExceeded"));
@@ -2612,24 +2703,46 @@
// Not possible
}
parameters.addParameter(name, value);
+ } else {
+ // Adjust the limit to account for a file part which is not added to the parameter map.
+ maxParameterCount--;
}
+ parts.add(part);
}
success = true;
} catch (InvalidContentTypeException e) {
parameters.setParseFailedReason(FailReason.INVALID_CONTENT_TYPE);
partsParseException = new ServletException(e);
- } catch (SizeException e) {
+ } catch (SizeException | FileCountLimitExceededException e) {
parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
checkSwallowInput();
partsParseException = new IllegalStateException(e);
- } catch (IOException e) {
+ } catch (IOException ioe) {
parameters.setParseFailedReason(FailReason.IO_ERROR);
- partsParseException = e;
+ partsParseException = ioe;
} catch (IllegalStateException e) {
// addParameters() will set parseFailedReason
checkSwallowInput();
partsParseException = e;
+ } finally {
+ /*
+ * GC will delete any temporary copies of uploaded files left in the work directory but if we know that
+ * the upload has failed then explicitly clean up now.
+ */
+ if (!success) {
+ parts.clear();
+ if (items != null) {
+ for (FileItem item : items) {
+ try {
+ item.delete();
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.warn(sm.getString("request.partCleanup.failed"), t);
+ }
+ }
+ }
+ }
}
} finally {
// This might look odd but is correct. setParseFailedReason() only
@@ -2680,11 +2793,11 @@
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
- } catch (IOException e) {
+ } catch (IOException ioe) {
if (log.isDebugEnabled()) {
- log.debug(sm.getString("request.session.failed", requestedSessionId, e.getMessage()), e);
+ log.debug(sm.getString("request.session.failed", requestedSessionId, ioe.getMessage()), ioe);
} else {
- log.info(sm.getString("request.session.failed", requestedSessionId, e.getMessage()));
+ log.info(sm.getString("request.session.failed", requestedSessionId, ioe.getMessage()));
}
session = null;
}
@@ -2693,6 +2806,8 @@
}
if (session != null) {
session.access();
+ // The client has chosen to join the session
+ session.setNew(false);
return session;
}
}
@@ -2733,9 +2848,8 @@
found = true;
break;
}
- } catch (IOException e) {
- // Ignore. Problems with this manager will be
- // handled elsewhere.
+ } catch (IOException ignore) {
+ // Error looking up session. Treat it as not found.
}
}
}
@@ -2845,7 +2959,7 @@
scookie.getValue().getByteChunk().setCharset(getCookieProcessor().getCharset());
cookie.setValue(unescape(scookie.getValue().toString()));
cookies[idx++] = cookie;
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException ignore) {
// Ignore bad cookie
}
}
@@ -2864,14 +2978,30 @@
parametersParsed = true;
+ /*
+ * When the request body is multipart/form-data, both the parts and the query string count towards
+ * maxParameterCount. If parseParts() is called before getParameterXXX() then the parts will be parsed before
+ * the query string. Otherwise, the query string will be parsed first.
+ *
+ * maxParameterCount must be respected regardless of which is parsed first.
+ *
+ * maxParameterCount is reset from the Connector at the start of every request.
+ *
+ * If parts are parsed first, non-file parts will be added to the parameter map and any files will reduce
+ * maxParameterCount by 1 so that when the query string is parsed the difference between the size of the
+ * parameter map and maxParameterCount will be the original maxParameterCount less the number of parts. i.e. the
+ * maxParameterCount applied to the query string will be the original maxParameterCount less the number of
+ * parts.
+ *
+ * If the query string is parsed first, all parameters will be added to the parameter map and, ignoring
+ * maxPartCount, the part limit will be set to the original maxParameterCount less the size of the parameter
+ * map. i.e. the maxParameterCount applied to the parts will be the original maxParameterCount less the number
+ * of query parameters.
+ */
Parameters parameters = coyoteRequest.getParameters();
boolean success = false;
try {
// Set this every time in case limit has been changed via JMX
- int maxParameterCount = getConnector().getMaxParameterCount();
- if (parts != null && maxParameterCount > 0) {
- maxParameterCount -= parts.size();
- }
parameters.setLimit(maxParameterCount);
// getCharacterEncoding() may have been overridden to search for
@@ -2935,17 +3065,18 @@
}
try {
readPostBodyFully(formData, len);
- } catch (IOException e) {
+ } catch (IOException ioe) {
// Client disconnect
Context context = getContext();
if (context != null && context.getLogger().isDebugEnabled()) {
- context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), e);
+ context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), ioe);
}
parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);
return;
}
parameters.processParameters(formData, 0, len);
- } else if ("chunked".equalsIgnoreCase(coyoteRequest.getHeader("transfer-encoding"))) {
+ } else if (coyoteRequest.protocol().equals("HTTP/2.0") ||
+ "chunked".equalsIgnoreCase(coyoteRequest.getHeader("transfer-encoding"))) {
byte[] formData = null;
try {
formData = readChunkedPostBody();
@@ -2957,12 +3088,12 @@
context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), ise);
}
return;
- } catch (IOException e) {
+ } catch (IOException ioe) {
// Client disconnect
parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);
Context context = getContext();
if (context != null && context.getLogger().isDebugEnabled()) {
- context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), e);
+ context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), ioe);
}
return;
}
@@ -3107,7 +3238,7 @@
List acceptLanguages;
try {
acceptLanguages = AcceptLanguage.parse(new StringReader(value));
- } catch (IOException e) {
+ } catch (IOException ioe) {
// Mal-formed headers are ignore. Do the same in the unlikely event
// of an IOException.
return;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/RequestFacade.java tomcat10-10.1.52/java/org/apache/catalina/connector/RequestFacade.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/RequestFacade.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/RequestFacade.java 2026-01-23 19:33:36.000000000 +0000
@@ -49,9 +49,6 @@
/**
* Facade class that wraps a Coyote request object. All methods are delegated to the wrapped request.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class RequestFacade implements HttpServletRequest {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/Response.java tomcat10-10.1.52/java/org/apache/catalina/connector/Response.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/Response.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/Response.java 2026-01-23 19:33:36.000000000 +0000
@@ -67,9 +67,6 @@
/**
* Wrapper object for the Coyote response.
- *
- * @author Remy Maucherat
- * @author Craig R. McClanahan
*/
public class Response implements HttpServletResponse {
@@ -1404,8 +1401,8 @@
redirectURLCC.append(':');
redirectURLCC.append(location, 0, location.length());
return redirectURLCC.toString();
- } catch (IOException e) {
- throw new IllegalArgumentException(location, e);
+ } catch (IOException ioe) {
+ throw new IllegalArgumentException(location, ioe);
}
} else if (leadingSlash || !UriUtil.hasScheme(location)) {
@@ -1446,8 +1443,8 @@
redirectURLCC.append(location, 0, location.length());
normalize(redirectURLCC);
- } catch (IOException e) {
- throw new IllegalArgumentException(location, e);
+ } catch (IOException ioe) {
+ throw new IllegalArgumentException(location, ioe);
}
return redirectURLCC.toString();
@@ -1481,8 +1478,8 @@
if (cc.endsWith("/.") || cc.endsWith("/..")) {
try {
cc.append('/');
- } catch (IOException e) {
- throw new IllegalArgumentException(cc.toString(), e);
+ } catch (IOException ioe) {
+ throw new IllegalArgumentException(cc.toString(), ioe);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/connector/ResponseFacade.java tomcat10-10.1.52/java/org/apache/catalina/connector/ResponseFacade.java
--- tomcat10-10.1.40/java/org/apache/catalina/connector/ResponseFacade.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/connector/ResponseFacade.java 2026-01-23 19:33:36.000000000 +0000
@@ -37,8 +37,6 @@
/**
* Facade class that wraps a Coyote response object. All methods are delegated to the wrapped response.
- *
- * @author Remy Maucherat
*/
public class ResponseFacade implements HttpServletResponse {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationContext.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationContext.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationContext.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationContext.java 2026-01-23 19:33:36.000000000 +0000
@@ -83,9 +83,6 @@
/**
* Standard implementation of ServletContext that represents a web application's execution environment. An
* instance of this class is associated with each instance of StandardContext.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class ApplicationContext implements ServletContext {
@@ -374,7 +371,7 @@
// From this point, the removal of path parameters, decoding and normalization is only for mapping purposes.
// Remove path parameters
- String uriToMap = stripPathParams(uri);
+ String uriToMap = org.apache.catalina.util.RequestUtil.stripPathParams(uri, null);
// Decode only if the uri derived from the provided path is expected to be encoded
if (getContext().getDispatchersUseEncodedPaths()) {
@@ -449,34 +446,6 @@
}
- // Package private to facilitate testing
- static String stripPathParams(String input) {
- // Shortcut
- if (input.indexOf(';') < 0) {
- return input;
- }
-
- StringBuilder sb = new StringBuilder(input.length());
- int pos = 0;
- int limit = input.length();
- while (pos < limit) {
- int nextSemiColon = input.indexOf(';', pos);
- if (nextSemiColon < 0) {
- nextSemiColon = limit;
- }
- sb.append(input, pos, nextSemiColon);
- int followingSlash = input.indexOf('/', nextSemiColon);
- if (followingSlash < 0) {
- pos = limit;
- } else {
- pos = followingSlash;
- }
- }
-
- return sb.toString();
- }
-
-
@Override
public URL getResource(String path) throws MalformedURLException {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationContextFacade.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationContextFacade.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationContextFacade.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationContextFacade.java 2026-01-23 19:33:36.000000000 +0000
@@ -51,8 +51,6 @@
/**
* Facade object which masks the internal ApplicationContext object from the web application.
- *
- * @author Remy Maucherat
*/
public class ApplicationContextFacade implements ServletContext {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationDispatcher.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationDispatcher.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationDispatcher.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationDispatcher.java 2026-01-23 19:33:36.000000000 +0000
@@ -56,8 +56,6 @@
* resource. This implementation allows application level servlets to wrap the request and/or response objects that are
* passed on to the called resource, as long as the wrapping classes extend
* jakarta.servlet.ServletRequestWrapper and jakarta.servlet.ServletResponseWrapper.
- *
- * @author Craig R. McClanahan
*/
final class ApplicationDispatcher implements AsyncDispatcher, RequestDispatcher {
@@ -364,7 +362,7 @@
} catch (IllegalStateException | IOException f) {
// Ignore
}
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
}
@@ -594,11 +592,11 @@
wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", wrapper.getName()),
StandardWrapper.getRootCause(e));
servletException = e;
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), t);
servletException =
- new ServletException(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), e);
+ new ServletException(sm.getString("applicationDispatcher.allocateException", wrapper.getName()), t);
// servlet = null; is already done so no need to do it explicitly
}
@@ -614,9 +612,9 @@
// Servlet Service Method is called by the FilterChain
} catch (BadRequestException | CloseNowException e) {
ioException = e;
- } catch (IOException e) {
- wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e);
- ioException = e;
+ } catch (IOException ioe) {
+ wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), ioe);
+ ioException = ioe;
} catch (UnavailableException e) {
wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", wrapper.getName()), e);
servletException = e;
@@ -646,11 +644,11 @@
} catch (ServletException e) {
wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e);
servletException = e;
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), t);
servletException = new ServletException(
- sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), e);
+ sm.getString("applicationDispatcher.deallocateException", wrapper.getName()), t);
}
// Reset the old context class loader
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationFilterChain.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationFilterChain.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationFilterChain.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationFilterChain.java 2026-01-23 19:33:36.000000000 +0000
@@ -40,8 +40,6 @@
* Implementation of jakarta.servlet.FilterChain used to manage the execution of a set of filters for a
* particular request. When the set of defined filters has all been executed, the next call to doFilter()
* will execute the servlet's service() method itself.
- *
- * @author Craig R. McClanahan
*/
public final class ApplicationFilterChain implements FilterChain {
@@ -165,10 +163,10 @@
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
- } catch (Throwable e) {
- e = ExceptionUtils.unwrapInvocationTargetException(e);
- ExceptionUtils.handleThrowable(e);
- throw new ServletException(sm.getString("filterChain.filter"), e);
+ } catch (Throwable t) {
+ t = ExceptionUtils.unwrapInvocationTargetException(t);
+ ExceptionUtils.handleThrowable(t);
+ throw new ServletException(sm.getString("filterChain.filter"), t);
}
return;
}
@@ -196,10 +194,10 @@
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
- } catch (Throwable e) {
- e = ExceptionUtils.unwrapInvocationTargetException(e);
- ExceptionUtils.handleThrowable(e);
- throw new ServletException(sm.getString("filterChain.servlet"), e);
+ } catch (Throwable t) {
+ t = ExceptionUtils.unwrapInvocationTargetException(t);
+ ExceptionUtils.handleThrowable(t);
+ throw new ServletException(sm.getString("filterChain.servlet"), t);
} finally {
if (dispatcherWrapsSameObject) {
lastServicedRequest.set(null);
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationFilterConfig.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationFilterConfig.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationFilterConfig.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationFilterConfig.java 2026-01-23 19:33:36.000000000 +0000
@@ -49,8 +49,6 @@
/**
* Implementation of a jakarta.servlet.FilterConfig useful in managing the filter instances instantiated
* when a web application is first started.
- *
- * @author Craig R. McClanahan
*/
public final class ApplicationFilterConfig implements FilterConfig, Serializable {
@@ -179,11 +177,8 @@
@Override
public String toString() {
- return "ApplicationFilterConfig[" + "name=" +
- filterDef.getFilterName() +
- ", filterClass=" +
- filterDef.getFilterClass() +
- ']';
+ return "ApplicationFilterConfig[" + "name=" + filterDef.getFilterName() + ", filterClass=" +
+ filterDef.getFilterClass() + ']';
}
// --------------------------------------------------------- Public Methods
@@ -323,8 +318,8 @@
try {
oname = new ObjectName(onameStr);
Registry.getRegistry(null).registerComponent(this, oname, null);
- } catch (Exception ex) {
- log.warn(sm.getString("applicationFilterConfig.jmxRegisterFail", getFilterClass(), getFilterName()), ex);
+ } catch (Exception e) {
+ log.warn(sm.getString("applicationFilterConfig.jmxRegisterFail", getFilterClass(), getFilterName()), e);
}
}
@@ -337,9 +332,9 @@
if (log.isDebugEnabled()) {
log.debug(sm.getString("applicationFilterConfig.jmxUnregister", getFilterClass(), getFilterName()));
}
- } catch (Exception ex) {
+ } catch (Exception e) {
log.warn(sm.getString("applicationFilterConfig.jmxUnregisterFail", getFilterClass(), getFilterName()),
- ex);
+ e);
}
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationFilterFactory.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationFilterFactory.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationFilterFactory.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationFilterFactory.java 2026-01-23 19:33:36.000000000 +0000
@@ -31,9 +31,6 @@
/**
* Factory for the creation and caching of Filters and creation of Filter Chains.
- *
- * @author Greg Murray
- * @author Remy Maucherat
*/
public final class ApplicationFilterFactory {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationHttpRequest.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationHttpRequest.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationHttpRequest.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationHttpRequest.java 2026-01-23 19:33:36.000000000 +0000
@@ -63,9 +63,6 @@
* WARNING: Due to Java's lack of support for multiple inheritance, all of the logic in
* ApplicationRequest is duplicated in ApplicationHttpRequest. Make sure that you keep these
* two classes in synchronization when making changes!
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
class ApplicationHttpRequest extends HttpServletRequestWrapper {
@@ -550,7 +547,7 @@
if (localSession != null && !localSession.isValid()) {
localSession = null;
}
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
if (localSession == null && create) {
@@ -596,7 +593,7 @@
Session session = null;
try {
session = manager.findSession(requestedSessionId);
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
return (session != null) && session.isValid();
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationHttpResponse.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationHttpResponse.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationHttpResponse.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationHttpResponse.java 2026-01-23 19:33:36.000000000 +0000
@@ -33,8 +33,6 @@
* WARNING: Due to Java's lack of support for multiple inheritance, all of the logic in
* ApplicationResponse is duplicated in ApplicationHttpResponse. Make sure that you keep these
* two classes in synchronization when making changes!
- *
- * @author Craig R. McClanahan
*/
class ApplicationHttpResponse extends HttpServletResponseWrapper {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationPushBuilder.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationPushBuilder.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationPushBuilder.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationPushBuilder.java 2026-01-23 19:33:36.000000000 +0000
@@ -293,7 +293,7 @@
org.apache.coyote.Request pushTarget = new org.apache.coyote.Request();
- pushTarget.method().setString(method);
+ pushTarget.setMethod(method);
// The next three are implied by the Javadoc getPath()
pushTarget.serverName().setString(baseRequest.getServerName());
pushTarget.setServerPort(baseRequest.getServerPort());
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationRequest.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationRequest.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationRequest.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationRequest.java 2026-01-23 19:33:36.000000000 +0000
@@ -36,8 +36,6 @@
* WARNING: Due to Java's lack of support for multiple inheritance, all of the logic in
* ApplicationRequest is duplicated in ApplicationHttpRequest. Make sure that you keep these
* two classes in synchronization when making changes!
- *
- * @author Craig R. McClanahan
*/
class ApplicationRequest extends ServletRequestWrapper {
@@ -59,8 +57,7 @@
*/
private static final Set specialsSet = new HashSet<>(Arrays.asList(specials));
- private static final int shortestSpecialNameLength =
- specialsSet.stream().mapToInt(String::length).min().getAsInt();
+ private static final int shortestSpecialNameLength = specialsSet.stream().mapToInt(String::length).min().getAsInt();
/**
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationResponse.java tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationResponse.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ApplicationResponse.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ApplicationResponse.java 2026-01-23 19:33:36.000000000 +0000
@@ -31,8 +31,6 @@
* WARNING: Due to Java's lack of support for multiple inheritance, all of the logic in
* ApplicationResponse is duplicated in ApplicationHttpResponse. Make sure that you keep these
* two classes in synchronization when making changes!
- *
- * @author Craig R. McClanahan
*/
class ApplicationResponse extends ServletResponseWrapper {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/AprLifecycleListener.java tomcat10-10.1.52/java/org/apache/catalina/core/AprLifecycleListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/AprLifecycleListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/AprLifecycleListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -19,6 +19,7 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.locks.Lock;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
@@ -63,12 +64,17 @@
// ---------------------------------------------- Constants
- protected static final int TCN_REQUIRED_MAJOR = 1;
- protected static final int TCN_REQUIRED_MINOR = 2;
- protected static final int TCN_REQUIRED_PATCH = 34;
+ private static final int TCN_1_REQUIRED_MINOR = 3;
+ private static final int TCN_1_REQUIRED_PATCH = 4;
+ private static final int TCN_1_RECOMMENDED_MINOR = 3;
+ private static final int TCN_1_RECOMMENDED_PATCH = 4;
+
+ protected static final int TCN_REQUIRED_MAJOR = 2;
+ protected static final int TCN_REQUIRED_MINOR = 0;
+ protected static final int TCN_REQUIRED_PATCH = 12;
protected static final int TCN_RECOMMENDED_MAJOR = 2;
protected static final int TCN_RECOMMENDED_MINOR = 0;
- protected static final int TCN_RECOMMENDED_PV = 5;
+ protected static final int TCN_RECOMMENDED_PV = 12;
// ---------------------------------------------- Properties
@@ -99,25 +105,27 @@
private static final int FIPS_OFF = 0;
- protected static final Object lock = new Object();
-
- // Guarded by lock
+ // Guarded APRStatus.getStatusLock()
private static int referenceCount = 0;
private boolean instanceInitialized = false;
public static boolean isAprAvailable() {
// https://bz.apache.org/bugzilla/show_bug.cgi?id=48613
- if (AprStatus.isInstanceCreated()) {
- synchronized (lock) {
+ if (org.apache.tomcat.jni.AprStatus.isInstanceCreated()) {
+ Lock writeLock = org.apache.tomcat.jni.AprStatus.getStatusLock().writeLock();
+ writeLock.lock();
+ try {
init();
+ } finally {
+ writeLock.unlock();
}
}
- return AprStatus.isAprAvailable();
+ return org.apache.tomcat.jni.AprStatus.isAprAvailable();
}
public AprLifecycleListener() {
- AprStatus.setInstanceCreated(true);
+ org.apache.tomcat.jni.AprStatus.setInstanceCreated(true);
}
// ---------------------------------------------- LifecycleListener Methods
@@ -131,7 +139,9 @@
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
- synchronized (lock) {
+ Lock writeLock = org.apache.tomcat.jni.AprStatus.getStatusLock().writeLock();
+ writeLock.lock();
+ try {
instanceInitialized = true;
if (!(event.getLifecycle() instanceof Server)) {
log.warn(sm.getString("listener.notServer", event.getLifecycle().getClass().getSimpleName()));
@@ -145,7 +155,7 @@
log.info(msg);
}
initInfoLogMessages.clear();
- if (AprStatus.isAprAvailable()) {
+ if (org.apache.tomcat.jni.AprStatus.isAprAvailable()) {
try {
initializeSSL();
} catch (Throwable t) {
@@ -156,15 +166,18 @@
}
// Failure to initialize FIPS mode is fatal
if (!(null == FIPSMode || "off".equalsIgnoreCase(FIPSMode)) && !isFIPSModeActive()) {
- String errorMessage = sm.getString("aprListener.initializeFIPSFailed");
- Error e = new Error(errorMessage);
+ Error e = new Error(sm.getString("aprListener.initializeFIPSFailed"));
// Log here, because thrown error might be not logged
- log.fatal(errorMessage, e);
+ log.fatal(e.getMessage(), e);
throw e;
}
+ } finally {
+ writeLock.unlock();
}
} else if (Lifecycle.AFTER_DESTROY_EVENT.equals(event.getType())) {
- synchronized (lock) {
+ Lock writeLock = org.apache.tomcat.jni.AprStatus.getStatusLock().writeLock();
+ writeLock.lock();
+ try {
// Instance may get destroyed without ever being initialized
if (instanceInitialized) {
referenceCount--;
@@ -173,7 +186,7 @@
// Still being used
return;
}
- if (!AprStatus.isAprAvailable()) {
+ if (!org.apache.tomcat.jni.AprStatus.isAprAvailable()) {
return;
}
try {
@@ -181,16 +194,18 @@
} catch (Throwable t) {
Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(throwable);
- log.info(sm.getString("aprListener.aprDestroy"));
+ log.warn(sm.getString("aprListener.aprDestroy"), throwable);
}
+ } finally {
+ writeLock.unlock();
}
}
}
private static void terminateAPR() {
- AprStatus.setAprInitialized(false);
- AprStatus.setAprAvailable(false);
+ org.apache.tomcat.jni.AprStatus.setAprInitialized(false);
+ org.apache.tomcat.jni.AprStatus.setAprAvailable(false);
fipsModeActive = false;
sslInitialized = false; // terminate() will clean the pool
// There could be unreferenced SSL_CTX still waiting for GC
@@ -199,13 +214,10 @@
}
private static void init() {
- int rqver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_REQUIRED_PATCH;
- int rcver = TCN_RECOMMENDED_MAJOR * 1000 + TCN_RECOMMENDED_MINOR * 100 + TCN_RECOMMENDED_PV;
-
- if (AprStatus.isAprInitialized()) {
+ if (org.apache.tomcat.jni.AprStatus.isAprInitialized()) {
return;
}
- AprStatus.setAprInitialized(true);
+ org.apache.tomcat.jni.AprStatus.setAprInitialized(true);
try {
Library.initialize(null);
@@ -239,9 +251,34 @@
}
return;
}
+
+ /*
+ * With parallel development of 1.x and 2.x there are now minimum and recommended versions for both branches.
+ *
+ * The minimum required version is increased when the Tomcat Native API is changed (typically extended) to
+ * include functionality that Tomcat expects to always be present.
+ *
+ * The minimum recommended version is increased when there is a change in Tomcat Native that while not required
+ * is recommended (such as bug fixes).
+ */
+ int rqver;
+ int rcver;
+ if (tcnMajor == 1) {
+ rqver = 1000 + TCN_1_REQUIRED_MINOR * 100 + TCN_1_REQUIRED_PATCH;
+ rcver = 1000 + TCN_1_RECOMMENDED_MINOR * 100 + TCN_1_RECOMMENDED_PATCH;
+ } else {
+ rqver = TCN_REQUIRED_MAJOR * 1000 + TCN_REQUIRED_MINOR * 100 + TCN_REQUIRED_PATCH;
+ rcver = TCN_RECOMMENDED_MAJOR * 1000 + TCN_RECOMMENDED_MINOR * 100 + TCN_RECOMMENDED_PV;
+ }
+
if (tcnVersion < rqver) {
- log.error(sm.getString("aprListener.tcnInvalid", Library.versionString(),
- TCN_REQUIRED_MAJOR + "." + TCN_REQUIRED_MINOR + "." + TCN_REQUIRED_PATCH));
+ if (tcnMajor == 1) {
+ log.error(sm.getString("aprListener.tcnInvalid.1", Library.versionString(),
+ "1." + TCN_1_REQUIRED_MINOR + "." + TCN_1_REQUIRED_PATCH));
+ } else {
+ log.error(sm.getString("aprListener.tcnInvalid", Library.versionString(),
+ TCN_REQUIRED_MAJOR + "." + TCN_REQUIRED_MINOR + "." + TCN_REQUIRED_PATCH));
+ }
try {
// Terminate the APR in case the version
// is below required.
@@ -253,14 +290,19 @@
return;
}
if (tcnVersion < rcver) {
- initInfoLogMessages.add(sm.getString("aprListener.tcnVersion", Library.versionString(),
- TCN_RECOMMENDED_MAJOR + "." + TCN_RECOMMENDED_MINOR + "." + TCN_RECOMMENDED_PV));
+ if (tcnMajor == 1) {
+ initInfoLogMessages.add(sm.getString("aprListener.tcnVersion.1", Library.versionString(),
+ "1." + TCN_1_RECOMMENDED_MINOR + "." + TCN_1_RECOMMENDED_PATCH));
+ } else {
+ initInfoLogMessages.add(sm.getString("aprListener.tcnVersion", Library.versionString(),
+ TCN_RECOMMENDED_MAJOR + "." + TCN_RECOMMENDED_MINOR + "." + TCN_RECOMMENDED_PV));
+ }
}
initInfoLogMessages
.add(sm.getString("aprListener.tcnValid", Library.versionString(), Library.aprVersionString()));
- AprStatus.setAprAvailable(true);
+ org.apache.tomcat.jni.AprStatus.setAprAvailable(true);
}
private static void initializeSSL() throws Exception {
@@ -290,7 +332,7 @@
method = clazz.getMethod(methodName, paramTypes);
method.invoke(null, paramValues);
- AprStatus.setOpenSSLVersion(SSL.version());
+ org.apache.tomcat.jni.AprStatus.setOpenSSLVersion(SSL.version());
// OpenSSL 3 onwards uses providers
boolean usingProviders = tcnMajor > 1 || (tcnVersion > 1233 && (SSL.version() & 0xF0000000L) > 0x20000000);
@@ -430,17 +472,17 @@
}
public void setUseOpenSSL(boolean useOpenSSL) {
- if (useOpenSSL != AprStatus.getUseOpenSSL()) {
- AprStatus.setUseOpenSSL(useOpenSSL);
+ if (useOpenSSL != org.apache.tomcat.jni.AprStatus.getUseOpenSSL()) {
+ org.apache.tomcat.jni.AprStatus.setUseOpenSSL(useOpenSSL);
}
}
public static boolean getUseOpenSSL() {
- return AprStatus.getUseOpenSSL();
+ return org.apache.tomcat.jni.AprStatus.getUseOpenSSL();
}
public static boolean isInstanceCreated() {
- return AprStatus.isInstanceCreated();
+ return org.apache.tomcat.jni.AprStatus.isInstanceCreated();
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/AprStatus.java tomcat10-10.1.52/java/org/apache/catalina/core/AprStatus.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/AprStatus.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/AprStatus.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,58 +18,56 @@
/**
* Holds APR status without the need to load other classes.
+ *
+ * @deprecated Unused. Use {@link org.apache.tomcat.jni.AprStatus} instead. This class will be removed in Tomcat 12
+ * onwards.
*/
+@Deprecated
public class AprStatus {
- private static volatile boolean aprInitialized = false;
- private static volatile boolean aprAvailable = false;
- private static volatile boolean useOpenSSL = true;
- private static volatile boolean instanceCreated = false;
- private static volatile int openSSLVersion = 0;
public static boolean isAprInitialized() {
- return aprInitialized;
+ return org.apache.tomcat.jni.AprStatus.isAprInitialized();
}
public static boolean isAprAvailable() {
- return aprAvailable;
+ return org.apache.tomcat.jni.AprStatus.isAprAvailable();
}
public static boolean getUseOpenSSL() {
- return useOpenSSL;
+ return org.apache.tomcat.jni.AprStatus.getUseOpenSSL();
}
public static boolean isInstanceCreated() {
- return instanceCreated;
+ return org.apache.tomcat.jni.AprStatus.isInstanceCreated();
}
public static void setAprInitialized(boolean aprInitialized) {
- AprStatus.aprInitialized = aprInitialized;
+ org.apache.tomcat.jni.AprStatus.setAprInitialized(aprInitialized);
}
public static void setAprAvailable(boolean aprAvailable) {
- AprStatus.aprAvailable = aprAvailable;
+ org.apache.tomcat.jni.AprStatus.setAprAvailable(aprAvailable);
}
public static void setUseOpenSSL(boolean useOpenSSL) {
- AprStatus.useOpenSSL = useOpenSSL;
+ org.apache.tomcat.jni.AprStatus.setUseOpenSSL(useOpenSSL);
}
public static void setInstanceCreated(boolean instanceCreated) {
- AprStatus.instanceCreated = instanceCreated;
+ org.apache.tomcat.jni.AprStatus.setInstanceCreated(instanceCreated);
}
/**
* @return the openSSLVersion
*/
public static int getOpenSSLVersion() {
- return openSSLVersion;
+ return org.apache.tomcat.jni.AprStatus.getOpenSSLVersion();
}
/**
* @param openSSLVersion the openSSLVersion to set
*/
public static void setOpenSSLVersion(int openSSLVersion) {
- AprStatus.openSSLVersion = openSSLVersion;
+ org.apache.tomcat.jni.AprStatus.setOpenSSLVersion(openSSLVersion);
}
-
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ContainerBase.java tomcat10-10.1.52/java/org/apache/catalina/core/ContainerBase.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ContainerBase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ContainerBase.java 2026-01-23 19:33:36.000000000 +0000
@@ -118,8 +118,6 @@
*
*
* Subclasses that fire additional events should document them in the class comments of the implementation class.
- *
- * @author Craig R. McClanahan
*/
public abstract class ContainerBase extends LifecycleMBeanBase implements Container {
@@ -754,12 +752,12 @@
for (Future result : results) {
try {
result.get();
- } catch (Throwable e) {
- log.error(sm.getString("containerBase.threadedStartFailed"), e);
+ } catch (Throwable t) {
+ log.error(sm.getString("containerBase.threadedStartFailed"), t);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
- multiThrowable.add(e);
+ multiThrowable.add(t);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/DefaultInstanceManager.java tomcat10-10.1.52/java/org/apache/catalina/core/DefaultInstanceManager.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/DefaultInstanceManager.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/DefaultInstanceManager.java 2026-01-23 19:33:36.000000000 +0000
@@ -189,8 +189,7 @@
}
/**
- * Call postConstruct method on the specified instance recursively from the deepest superclass
- * to actual class.
+ * Call postConstruct method on the specified instance recursively from the deepest superclass to actual class.
*
* @param instance object to call postconstruct methods on
* @param clazz (super) class to examine for postConstruct annotation.
@@ -227,8 +226,7 @@
/**
- * Call preDestroy method on the specified instance recursively from the deepest superclass
- * to actual class.
+ * Call preDestroy method on the specified instance recursively from the deepest superclass to actual class.
*
* @param instance object to call preDestroy methods on
* @param clazz (super) class to examine for preDestroy annotation.
@@ -330,13 +328,11 @@
} else if (JPA_PRESENT && (persistenceContextAnnotation =
method.getAnnotation(PersistenceContext.class)) != null) {
annotations.add(new AnnotationCacheEntry(method.getName(), method.getParameterTypes(),
- persistenceContextAnnotation.name(),
- AnnotationCacheEntryType.SETTER));
+ persistenceContextAnnotation.name(), AnnotationCacheEntryType.SETTER));
} else if (JPA_PRESENT &&
(persistenceUnitAnnotation = method.getAnnotation(PersistenceUnit.class)) != null) {
annotations.add(new AnnotationCacheEntry(method.getName(), method.getParameterTypes(),
- persistenceUnitAnnotation.name(),
- AnnotationCacheEntryType.SETTER));
+ persistenceUnitAnnotation.name(), AnnotationCacheEntryType.SETTER));
}
}
@@ -383,17 +379,15 @@
AnnotationCacheEntryType.FIELD));
} else if (WS_PRESENT &&
(webServiceRefAnnotation = field.getAnnotation(WebServiceRef.class)) != null) {
- annotations.add(new AnnotationCacheEntry(fieldName, null,
- webServiceRefAnnotation.name(), AnnotationCacheEntryType.FIELD));
+ annotations.add(new AnnotationCacheEntry(fieldName, null, webServiceRefAnnotation.name(),
+ AnnotationCacheEntryType.FIELD));
} else if (JPA_PRESENT && (persistenceContextAnnotation =
field.getAnnotation(PersistenceContext.class)) != null) {
annotations.add(new AnnotationCacheEntry(fieldName, null,
- persistenceContextAnnotation.name(),
- AnnotationCacheEntryType.FIELD));
+ persistenceContextAnnotation.name(), AnnotationCacheEntryType.FIELD));
} else if (JPA_PRESENT &&
(persistenceUnitAnnotation = field.getAnnotation(PersistenceUnit.class)) != null) {
- annotations.add(new AnnotationCacheEntry(fieldName, null,
- persistenceUnitAnnotation.name(),
+ annotations.add(new AnnotationCacheEntry(fieldName, null, persistenceUnitAnnotation.name(),
AnnotationCacheEntryType.FIELD));
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java tomcat10-10.1.52/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -78,9 +78,9 @@
}
/**
- * The first access to {@link DriverManager} will trigger the loading of all {@link java.sql.Driver}s in the
- * current class loader. The web application level memory leak protection can take care of this in most cases but
- * triggering the loading here has fewer side effects.
+ * The first access to {@link DriverManager} will trigger the loading of all {@link java.sql.Driver}s in the current
+ * class loader. The web application level memory leak protection can take care of this in most cases but triggering
+ * the loading here has fewer side effects.
*/
private boolean driverManagerProtection = true;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/LocalStrings.properties tomcat10-10.1.52/java/org/apache/catalina/core/LocalStrings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/core/LocalStrings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/LocalStrings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -90,9 +90,11 @@
aprListener.skipFIPSInitialization=Already in FIPS mode; skipping FIPS initialization.
aprListener.sslInit=Failed to initialize the SSLEngine.
aprListener.sslRequired=[{0}] is not a valid value for SSLEngine when using version [{1}] of the Tomcat Native library since SSL is required for version 2.x onwards.
-aprListener.tcnInvalid=An incompatible version [{0}] of the Apache Tomcat Native library is installed, while Tomcat requires version [{1}]
+aprListener.tcnInvalid=An incompatible version [{0}] of the Apache Tomcat Native library is installed, while Tomcat requires at least version [{1}]
+aprListener.tcnInvalid.1=An incompatible version [{0}] of the Apache Tomcat Native library is installed, while Tomcat requires at least version [{1}] of Tomcat Native 1.x
aprListener.tcnValid=Loaded Apache Tomcat Native library [{0}] using APR version [{1}].
aprListener.tcnVersion=An older version [{0}] of the Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of [{1}]
+aprListener.tcnVersion.1=An older version [{0}] of the Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of [{1}] of Tomcat Native 1.x
aprListener.tooLateForFIPSMode=Cannot setFIPSMode: SSL has already been initialized
aprListener.tooLateForSSLEngine=Cannot setSSLEngine: SSL has already been initialized
aprListener.tooLateForSSLRandomSeed=Cannot setSSLRandomSeed: SSL has already been initialized
@@ -276,7 +278,9 @@
standardHost.notContext=Child of a Host must be a Context
standardHost.nullName=Host name is required
standardHost.problematicAppBase=Using an empty string for appBase on host [{0}] will set it to CATALINA_BASE, which is a bad idea
+standardHost.problematicAppBaseParent=appBase on host [{0}] is a parent folder of CATALINA_BASE, which is a bad idea
standardHost.problematicLegacyAppBase=Using an empty string for legacyAppBase on host [{0}] will set it to CATALINA_BASE, which is a bad idea
+standardHost.problematicLegacyAppBaseParent=legacyAppBase on host [{0}] is a parent folder of CATALINA_BASE, which is a bad idea
standardHostValve.customStatusFailed=Custom error page [{0}] could not be dispatched correctly
standardHostValve.exception=Exception Processing [{0}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/core/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/core/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -276,7 +276,9 @@
standardHost.notContext=Host の子供はContextでなければいけません
standardHost.nullName=ホスト名が必要です
standardHost.problematicAppBase=ホスト [{0}] のappBaseに空の文字列を使用すると、CATALINA_BASEに設定されますが、これは悪い考えです
+standardHost.problematicAppBaseParent=Host [{0}] の appBase は CATALINA_BASE の親フォルダですが、これは適切ではありません
standardHost.problematicLegacyAppBase=ホスト [{0}] のlegacyAppBaseに空の文字列を使用すると、CATALINA_BASEに設定されます。これは悪い考えです
+standardHost.problematicLegacyAppBaseParent=Host [{0}] の legacyAppBase は CATALINA_BASE の親フォルダですが、これは適切ではありません
standardHostValve.customStatusFailed=カスタムエラーページ [{0}] を正しくディスパッチできませんでした
standardHostValve.exception=例外処理 [{0}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/core/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/core/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -28,17 +28,22 @@
applicationHttpRequest.sessionEndAccessFail=Исключение вызвало прекращение доступа к сессии при очистке запроса
aprListener.initializingFIPS=Инициализируется режим FIPS...
+aprListener.tcnVersion=Была обнаружена более старая версия [{0}] библиотеки Apache Tomcat Native, в то время как Tomcat рекомендует использовать как минимум версию [{1}]
filterChain.filter=При выполнении фильтра выброшено исключение
+naming.addEnvEntry=Добавляется переменная окружения [{0}]
naming.unbindFailed=Ошибка при отвязывании объекта: [{0}]
naming.wsdlFailed=wsdl файл не найден: [{0}]
standardContext.filterStart=Ошибка при старте фильтра [{0}]
standardContext.invalidWrapperClass=[{0}] не является подклассом StandardWrapper
+standardContext.managerFail=Невозможно запустить менеджер сессий
+standardContext.notStarted=Контекст с именем [{0}] ещё небыл запущен
standardContext.parameter.duplicate=Дублированный параметр инициализации контекста [{0}]
standardContext.predestroy.duplicate=Дублированное определение метода @PreDestroy для класса [{0}]
standardContext.securityConstraint.mixHttpMethod=Запрещено смешивать и в одной и той же коллекции веб-ресурсов
+standardContext.securityConstraint.pattern=Некорректный [{0}] в ограничении безопасности
standardContext.startingContext=Ошибка запуска контекста с именем [{0}]
standardWrapper.allocate=Ошибка при выделении экземпляра сервлета
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/NamingContextListener.java tomcat10-10.1.52/java/org/apache/catalina/core/NamingContextListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/NamingContextListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/NamingContextListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -76,8 +76,6 @@
/**
* Helper class used to initialize and populate the JNDI context associated with each context and server.
- *
- * @author Remy Maucherat
*/
public class NamingContextListener implements LifecycleListener, PropertyChangeListener {
@@ -235,7 +233,7 @@
try {
createNamingContext();
} catch (NamingException e) {
- log.error(sm.getString("naming.namingContextCreationFailed", e));
+ log.error(sm.getString("naming.namingContextCreationFailed", container), e);
}
namingResources.addPropertyChangeListener(this);
@@ -248,7 +246,7 @@
ContextBindings.bindClassLoader(container, token,
((Context) container).getLoader().getClassLoader());
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", container), e);
}
}
@@ -257,7 +255,7 @@
try {
ContextBindings.bindClassLoader(container, token, this.getClass().getClassLoader());
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", container), e);
}
if (container instanceof StandardServer) {
((StandardServer) container).setGlobalNamingContext(namingContext);
@@ -491,6 +489,13 @@
} else {
compCtx = namingContext.createSubcontext("comp");
envCtx = compCtx.createSubcontext("env");
+ /*
+ * Jakarta Platform Specification, 5.2.2: Application Component Environment Namespaces
+ *
+ * "java:module" and "java:comp" refer to the same namespace in a web module (i.e. a web application).
+ * Implement this by binding the "comp" sub-context we just created to the "module" name as well.
+ */
+ namingContext.bind("module", compCtx);
}
int i;
@@ -565,7 +570,7 @@
// Ignore because UserTransaction was obviously
// added via ResourceLink
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", "UserTransaction"), e);
}
}
@@ -574,7 +579,7 @@
try {
compCtx.bind("Resources", ((Context) container).getResources());
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", "Resources"), e);
}
}
@@ -648,7 +653,7 @@
createSubcontexts(envCtx, ejb.getName());
envCtx.bind(ejb.getName(), ref);
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", ejb.getName()), e);
}
}
@@ -748,7 +753,7 @@
createSubcontexts(envCtx, env.getName());
envCtx.bind(env.getName(), value);
} catch (NamingException e) {
- log.error(sm.getString("naming.invalidEnvEntryValue", e));
+ log.error(sm.getString("naming.invalidEnvEntryValue", env.getName()), e);
}
}
}
@@ -839,7 +844,7 @@
log.debug(sm.getString("naming.addSlash", service.getWsdlfile()));
}
} catch (MalformedURLException e) {
- log.error(sm.getString("naming.wsdlFailed", e));
+ log.error(sm.getString("naming.wsdlFailed", service.getWsdlfile()), e);
}
}
if (wsdlURL == null) {
@@ -874,7 +879,7 @@
log.debug(sm.getString("naming.addSlash", service.getJaxrpcmappingfile()));
}
} catch (MalformedURLException e) {
- log.error(sm.getString("naming.wsdlFailed", e));
+ log.error(sm.getString("naming.wsdlFailed", service.getJaxrpcmappingfile()), e);
}
}
if (jaxrpcURL == null) {
@@ -935,7 +940,7 @@
createSubcontexts(envCtx, service.getName());
envCtx.bind(service.getName(), ref);
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", service.getName()), e);
}
}
@@ -970,7 +975,7 @@
createSubcontexts(envCtx, resource.getName());
envCtx.bind(resource.getName(), ref);
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", resource.getName()), e);
}
if (("javax.sql.DataSource".equals(ref.getClassName()) ||
@@ -982,7 +987,7 @@
Registry.getRegistry(null).registerComponent(actualResource, on, null);
objectNames.put(resource.getName(), on);
} catch (Exception e) {
- log.warn(sm.getString("naming.jmxRegistrationFailed", e));
+ log.warn(sm.getString("naming.jmxRegistrationFailed", resource.getName()), e);
}
// Bug 63210. DBCP2 DataSources require an explicit close. This goes
// further and cleans up and AutoCloseable DataSource by default.
@@ -1022,7 +1027,7 @@
createSubcontexts(envCtx, resourceEnvRef.getName());
envCtx.bind(resourceEnvRef.getName(), ref);
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", resourceEnvRef.getName()), e);
}
}
@@ -1054,7 +1059,7 @@
createSubcontexts(envCtx, resourceLink.getName());
ctx.bind(resourceLink.getName(), ref);
} catch (NamingException e) {
- log.error(sm.getString("naming.bindFailed", e));
+ log.error(sm.getString("naming.bindFailed", resourceLink.getName()), e);
}
ResourceLinkFactory.registerGlobalResourceAccess(getGlobalNamingContext(), resourceLink.getName(),
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/OpenSSLLifecycleListener.java tomcat10-10.1.52/java/org/apache/catalina/core/OpenSSLLifecycleListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/OpenSSLLifecycleListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/OpenSSLLifecycleListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -125,7 +125,7 @@
} catch (Throwable t) {
Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(throwable);
- log.info(sm.getString("openssllistener.destroy"));
+ log.warn(sm.getString("openssllistener.destroy"), throwable);
}
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/PropertiesRoleMappingListener.java tomcat10-10.1.52/java/org/apache/catalina/core/PropertiesRoleMappingListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/PropertiesRoleMappingListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/PropertiesRoleMappingListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -111,9 +111,9 @@
Context context = (Context) event.getLifecycle();
try (Resource resource = context.findConfigFileResource(roleMappingFile)) {
props.load(resource.getInputStream());
- } catch (IOException e) {
+ } catch (IOException ioe) {
throw new IllegalStateException(
- sm.getString("propertiesRoleMappingListener.roleMappingFileFail", roleMappingFile), e);
+ sm.getString("propertiesRoleMappingListener.roleMappingFileFail", roleMappingFile), ioe);
}
int linkCount = 0;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardContext.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardContext.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardContext.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardContext.java 2026-01-23 19:33:36.000000000 +0000
@@ -42,6 +42,7 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
@@ -141,9 +142,6 @@
/**
* Standard implementation of the Context interface. Each child container must be a Wrapper implementation to
* process the requests directed to a particular servlet.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class StandardContext extends ContainerBase implements Context, NotificationEmitter {
@@ -423,7 +421,7 @@
/**
* The MIME mappings for this web application, keyed by extension.
*/
- private final Map mimeMappings = new HashMap<>();
+ private final ConcurrentMap mimeMappings = new ConcurrentHashMap<>();
/**
@@ -2454,8 +2452,8 @@
if (!workDir.isAbsolute()) {
try {
workDir = new File(getCatalinaBase().getCanonicalFile(), getWorkDir());
- } catch (IOException e) {
- log.warn(sm.getString("standardContext.workPath", getName()), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("standardContext.workPath", getName()), ioe);
}
}
return workDir.getAbsolutePath();
@@ -2827,12 +2825,8 @@
@Override
public void addMimeMapping(String extension, String mimeType) {
-
- synchronized (mimeMappings) {
- mimeMappings.put(extension.toLowerCase(Locale.ENGLISH), mimeType);
- }
+ mimeMappings.put(extension.toLowerCase(Locale.ENGLISH), mimeType);
fireContainerEvent("addMimeMapping", extension);
-
}
@@ -3106,9 +3100,7 @@
@Override
public String[] findMimeMappings() {
- synchronized (mimeMappings) {
- return mimeMappings.keySet().toArray(new String[0]);
- }
+ return mimeMappings.keySet().toArray(new String[0]);
}
@@ -3403,12 +3395,8 @@
@Override
public void removeMimeMapping(String extension) {
-
- synchronized (mimeMappings) {
- mimeMappings.remove(extension);
- }
+ mimeMappings.remove(extension);
fireContainerEvent("removeMimeMapping", extension);
-
}
@@ -4108,7 +4096,7 @@
Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(throwable);
getLogger().error(sm.getString("standardContext.listenerStop", listeners[j].getClass().getName()),
- throwable);
+ throwable);
ok = false;
}
}
@@ -4130,7 +4118,7 @@
Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(throwable);
getLogger().error(sm.getString("standardContext.listenerStop", listeners[j].getClass().getName()),
- throwable);
+ throwable);
ok = false;
}
}
@@ -4403,8 +4391,8 @@
if ((getCluster() != null) && distributable) {
try {
contextManager = getCluster().createManager(getName());
- } catch (Exception ex) {
- log.error(sm.getString("standardContext.cluster.managerError"), ex);
+ } catch (Exception e) {
+ log.error(sm.getString("standardContext.cluster.managerError"), e);
ok = false;
}
} else {
@@ -4763,8 +4751,8 @@
// This object will no longer be visible or used.
try {
resetContext();
- } catch (Exception ex) {
- log.error(sm.getString("standardContext.resetContextFail", getName()), ex);
+ } catch (Exception e) {
+ log.error(sm.getString("standardContext.resetContextFail", getName()), e);
}
// reset the instance manager
@@ -5012,9 +5000,8 @@
if (isUseNaming()) {
try {
ContextBindings.bindThread(this, getNamingToken());
- } catch (NamingException e) {
- // Silent catch, as this is a normal case during the early
- // startup stages
+ } catch (NamingException ignore) {
+ // Silent catch, as this is a normal case during the early startup stages
}
}
@@ -5349,8 +5336,9 @@
try {
catalinaHomePath = getCatalinaBase().getCanonicalPath();
dir = new File(catalinaHomePath, workDir);
- } catch (IOException e) {
- log.warn(sm.getString("standardContext.workCreateException", workDir, getCatalinaBase(), getName()), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("standardContext.workCreateException", workDir, getCatalinaBase(), getName()),
+ ioe);
}
}
if (!dir.mkdirs() && !dir.isDirectory()) {
@@ -5435,11 +5423,8 @@
@Override
protected String getObjectNameKeyProperties() {
- return "j2eeType=WebModule," + getObjectKeyPropertiesNameOnly() +
- ",J2EEApplication=" +
- getJ2EEApplication() +
- ",J2EEServer=" +
- getJ2EEServer();
+ return "j2eeType=WebModule," + getObjectKeyPropertiesNameOnly() + ",J2EEApplication=" + getJ2EEApplication() +
+ ",J2EEServer=" + getJ2EEServer();
}
private String getObjectKeyPropertiesNameOnly() {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardContextValve.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardContextValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardContextValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardContextValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -34,8 +34,6 @@
* Valve that implements the default basic behavior for the StandardContext container implementation.
*
* USAGE CONSTRAINT: This implementation is likely to be useful only when processing HTTP requests.
- *
- * @author Craig R. McClanahan
*/
final class StandardContextValve extends ValveBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardEngine.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardEngine.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardEngine.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardEngine.java 2026-01-23 19:33:36.000000000 +0000
@@ -45,8 +45,6 @@
/**
* Standard implementation of the Engine interface. Each child container must be a Host implementation to process
* the specific fully qualified host name of that virtual host.
- *
- * @author Craig R. McClanahan
*/
public class StandardEngine extends ContainerBase implements Engine {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardEngineValve.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardEngineValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardEngineValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardEngineValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -29,8 +29,6 @@
* Valve that implements the default basic behavior for the StandardEngine container implementation.
*
* USAGE CONSTRAINT: This implementation is likely to be useful only when processing HTTP requests.
- *
- * @author Craig R. McClanahan
*/
final class StandardEngineValve extends ValveBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardHost.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardHost.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardHost.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardHost.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,6 +18,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -49,9 +50,6 @@
/**
* Standard implementation of the Host interface. Each child container must be a Context implementation to
* process the requests directed to a particular web application.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class StandardHost extends ContainerBase implements Host {
@@ -232,6 +230,12 @@
// Ignore
}
+ Path appBasePath = file.toPath();
+ Path basePath = getCatalinaBase().toPath();
+ if (basePath.startsWith(appBasePath)) {
+ log.warn(sm.getString("standardHost.problematicAppBaseParent", getName()));
+ }
+
this.appBaseFile = file;
return file;
}
@@ -275,6 +279,12 @@
// Ignore
}
+ Path appBasePath = file.toPath();
+ Path basePath = getCatalinaBase().toPath();
+ if (basePath.startsWith(appBasePath)) {
+ log.warn(sm.getString("standardHost.problematicLegacyAppBaseParent", getName()));
+ }
+
this.legacyAppBaseFile = file;
return file;
}
@@ -331,7 +341,8 @@
}
try {
file = file.getCanonicalFile();
- } catch (IOException e) {// ignore
+ } catch (IOException ignore) {
+ // Ignore
}
this.hostConfigBase = file;
return file;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardHostValve.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardHostValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardHostValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardHostValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -44,9 +44,6 @@
* Valve that implements the default basic behavior for the StandardHost container implementation.
*
* USAGE CONSTRAINT: This implementation is likely to be useful only when processing HTTP requests.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
final class StandardHostValve extends ValveBase {
@@ -212,8 +209,8 @@
response.finishResponse();
} catch (ClientAbortException e) {
// Ignore
- } catch (IOException e) {
- container.getLogger().warn(sm.getString("standardHostValve.exception", errorPage), e);
+ } catch (IOException ioe) {
+ container.getLogger().warn(sm.getString("standardHostValve.exception", errorPage), ioe);
}
}
}
@@ -266,8 +263,8 @@
if (custom(request, response, errorPage)) {
try {
response.finishResponse();
- } catch (IOException e) {
- container.getLogger().warn(sm.getString("standardHostValve.exception", errorPage), e);
+ } catch (IOException ioe) {
+ container.getLogger().warn(sm.getString("standardHostValve.exception", errorPage), ioe);
}
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardPipeline.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardPipeline.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardPipeline.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardPipeline.java 2026-01-23 19:33:36.000000000 +0000
@@ -43,8 +43,6 @@
* This implementation assumes that no calls to addValve() or removeValve are allowed while a
* request is currently being processed. Otherwise, the mechanism by which per-thread state is maintained will need to
* be modified.
- *
- * @author Craig R. McClanahan
*/
public class StandardPipeline extends LifecycleBase implements Pipeline {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardServer.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardServer.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardServer.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardServer.java 2026-01-23 19:33:36.000000000 +0000
@@ -62,8 +62,6 @@
/**
* Standard implementation of the Server interface, available for use (but not required) when deploying and
* starting Catalina.
- *
- * @author Craig R. McClanahan
*/
public final class StandardServer extends LifecycleMBeanBase implements Server {
@@ -491,14 +489,14 @@
awaitSocket = null;
try {
s.close();
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignored
}
}
t.interrupt();
try {
t.join(1000);
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignore) {
// Ignored
}
}
@@ -531,9 +529,9 @@
// Set up a server socket to wait on
try {
awaitSocket = new ServerSocket(getPortWithOffset(), 1, InetAddress.getByName(address));
- } catch (IOException e) {
+ } catch (IOException ioe) {
log.error(sm.getString("standardServer.awaitSocket.fail", address, String.valueOf(getPortWithOffset()),
- String.valueOf(getPort()), String.valueOf(getPortOffset())), e);
+ String.valueOf(getPort()), String.valueOf(getPortOffset())), ioe);
return;
}
@@ -566,12 +564,12 @@
} catch (AccessControlException ace) {
log.warn(sm.getString("standardServer.accept.security"), ace);
continue;
- } catch (IOException e) {
+ } catch (IOException ioe) {
if (stopAwait) {
// Wait was aborted with socket.close()
break;
}
- log.error(sm.getString("standardServer.accept.error"), e);
+ log.error(sm.getString("standardServer.accept.error"), ioe);
break;
}
@@ -587,8 +585,8 @@
int ch;
try {
ch = stream.read();
- } catch (IOException e) {
- log.warn(sm.getString("standardServer.accept.readError"), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("standardServer.accept.readError"), ioe);
ch = -1;
}
// Control character or EOF (-1) terminates loop
@@ -604,7 +602,7 @@
if (socket != null) {
socket.close();
}
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
}
@@ -627,7 +625,7 @@
if (serverSocket != null) {
try {
serverSocket.close();
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardService.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardService.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardService.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardService.java 2026-01-23 19:33:36.000000000 +0000
@@ -46,8 +46,6 @@
/**
* Standard implementation of the Service interface. The associated Container is generally an instance of
* Engine, but this is not required.
- *
- * @author Craig R. McClanahan
*/
public class StandardService extends LifecycleMBeanBase implements Service {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardWrapper.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardWrapper.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardWrapper.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardWrapper.java 2026-01-23 19:33:36.000000000 +0000
@@ -65,9 +65,6 @@
/**
* Standard implementation of the Wrapper interface that represents an individual servlet definition. No child
* Containers are allowed, and the parent Container must be a Context.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class StandardWrapper extends ContainerBase implements ServletConfig, Wrapper, NotificationEmitter {
@@ -585,9 +582,9 @@
countAllocated.incrementAndGet();
} catch (ServletException e) {
throw e;
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- throw new ServletException(sm.getString("standardWrapper.allocate"), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ throw new ServletException(sm.getString("standardWrapper.allocate"), t);
}
}
if (!instanceInitialized) {
@@ -722,8 +719,8 @@
try {
jspMonitorON = new ObjectName(oname.toString());
Registry.getRegistry(null).registerComponent(instance, jspMonitorON, null);
- } catch (Exception ex) {
- log.warn(sm.getString("standardWrapper.jspMonitorError", instance));
+ } catch (Exception e) {
+ log.warn(sm.getString("standardWrapper.jspMonitorError", instance), e);
}
}
}
@@ -766,8 +763,8 @@
unavailable(null);
// Restore the context ClassLoader
throw new ServletException(sm.getString("standardWrapper.notServlet", servletClass), e);
- } catch (Throwable e) {
- Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(e);
+ } catch (Throwable t) {
+ Throwable throwable = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(throwable);
unavailable(null);
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardWrapperFacade.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardWrapperFacade.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardWrapperFacade.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardWrapperFacade.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,8 +25,6 @@
/**
* Facade for the StandardWrapper object.
- *
- * @author Remy Maucherat
*/
public final class StandardWrapperFacade implements ServletConfig {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/StandardWrapperValve.java tomcat10-10.1.52/java/org/apache/catalina/core/StandardWrapperValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/StandardWrapperValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/StandardWrapperValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -44,8 +44,6 @@
/**
* Valve that implements the default basic behavior for the StandardWrapper container implementation.
- *
- * @author Craig R. McClanahan
*/
final class StandardWrapperValve extends ValveBase {
@@ -122,11 +120,11 @@
StandardWrapper.getRootCause(e));
throwable = e;
exception(request, response, e);
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), e);
- throwable = e;
- exception(request, response, e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ container.getLogger().error(sm.getString("standardWrapper.allocateException", wrapper.getName()), t);
+ throwable = t;
+ exception(request, response, t);
// servlet = null; is set here
}
@@ -183,11 +181,11 @@
}
throwable = e;
exception(request, response, e);
- } catch (IOException e) {
+ } catch (IOException ioe) {
container.getLogger()
- .error(sm.getString("standardWrapper.serviceException", wrapper.getName(), context.getName()), e);
- throwable = e;
- exception(request, response, e);
+ .error(sm.getString("standardWrapper.serviceException", wrapper.getName(), context.getName()), ioe);
+ throwable = ioe;
+ exception(request, response, ioe);
} catch (UnavailableException e) {
container.getLogger()
.error(sm.getString("standardWrapper.serviceException", wrapper.getName(), context.getName()), e);
@@ -203,12 +201,12 @@
}
throwable = e;
exception(request, response, e);
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
container.getLogger()
- .error(sm.getString("standardWrapper.serviceException", wrapper.getName(), context.getName()), e);
- throwable = e;
- exception(request, response, e);
+ .error(sm.getString("standardWrapper.serviceException", wrapper.getName(), context.getName()), t);
+ throwable = t;
+ exception(request, response, t);
} finally {
// Release the filter chain (if any) for this request
if (filterChain != null) {
@@ -220,12 +218,12 @@
if (servlet != null) {
wrapper.deallocate(servlet);
}
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- container.getLogger().error(sm.getString("standardWrapper.deallocateException", wrapper.getName()), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ container.getLogger().error(sm.getString("standardWrapper.deallocateException", wrapper.getName()), t);
if (throwable == null) {
- throwable = e;
- exception(request, response, e);
+ throwable = t;
+ exception(request, response, t);
}
}
@@ -235,11 +233,11 @@
if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- container.getLogger().error(sm.getString("standardWrapper.unloadException", wrapper.getName()), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ container.getLogger().error(sm.getString("standardWrapper.unloadException", wrapper.getName()), t);
if (throwable == null) {
- exception(request, response, e);
+ exception(request, response, t);
}
}
long t2 = System.currentTimeMillis();
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/core/ThreadLocalLeakPreventionListener.java tomcat10-10.1.52/java/org/apache/catalina/core/ThreadLocalLeakPreventionListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/core/ThreadLocalLeakPreventionListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/core/ThreadLocalLeakPreventionListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -73,8 +73,7 @@
stopIdleThreads((Context) lifecycle);
}
} catch (Exception e) {
- String msg = sm.getString("threadLocalLeakPreventionListener.lifecycleEvent.error", event);
- log.error(msg, e);
+ log.error(sm.getString("threadLocalLeakPreventionListener.lifecycleEvent.error", event), e);
}
}
@@ -83,8 +82,7 @@
try {
super.containerEvent(event);
} catch (Exception e) {
- String msg = sm.getString("threadLocalLeakPreventionListener.containerEvent.error", event);
- log.error(msg, e);
+ log.error(sm.getString("threadLocalLeakPreventionListener.containerEvent.error", event), e);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/deploy/NamingResourcesImpl.java tomcat10-10.1.52/java/org/apache/catalina/deploy/NamingResourcesImpl.java
--- tomcat10-10.1.40/java/org/apache/catalina/deploy/NamingResourcesImpl.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/deploy/NamingResourcesImpl.java 2026-01-23 19:33:36.000000000 +0000
@@ -61,8 +61,6 @@
/**
* Holds and manages the naming resources defined in the Jakarta EE Naming Context and their associated JNDI context.
- *
- * @author Remy Maucherat
*/
public class NamingResourcesImpl extends LifecycleMBeanBase implements Serializable, NamingResources {
@@ -513,8 +511,8 @@
/**
- * @return the array of defined environment entries for this web application. If none have been defined, a zero-length
- * array is returned.
+ * @return the array of defined environment entries for this web application. If none have been defined, a
+ * zero-length array is returned.
*/
public ContextEnvironment[] findEnvironments() {
@@ -649,8 +647,8 @@
/**
- * @return the array of resource environment reference names for this web application. If none have been specified, a
- * zero-length array is returned.
+ * @return the array of resource environment reference names for this web application. If none have been specified,
+ * a zero-length array is returned.
*/
public ContextResourceEnvRef[] findResourceEnvRefs() {
@@ -977,10 +975,10 @@
try {
m = resource.getClass().getMethod(closeMethod, (Class>[]) null);
} catch (SecurityException e) {
- log.debug(sm.getString("namingResources.cleanupCloseSecurity", closeMethod, name, container));
+ log.debug(sm.getString("namingResources.cleanupCloseSecurity", closeMethod, name, container), e);
return;
} catch (NoSuchMethodException e) {
- log.debug(sm.getString("namingResources.cleanupNoClose", name, container, closeMethod));
+ log.debug(sm.getString("namingResources.cleanupNoClose", name, container, closeMethod), e);
return;
}
try {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/Constants.java tomcat10-10.1.52/java/org/apache/catalina/filters/Constants.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/Constants.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/Constants.java 2026-01-23 19:33:36.000000000 +0000
@@ -16,11 +16,10 @@
*/
package org.apache.catalina.filters;
+import org.apache.tomcat.util.http.Method;
/**
* Manifest constants for this Java package.
- *
- * @author Craig R. McClanahan
*/
public final class Constants {
@@ -44,7 +43,8 @@
*/
public static final String CSRF_NONCE_REQUEST_PARAM_NAME_KEY = "org.apache.catalina.filters.CSRF_NONCE_PARAM_NAME";
- public static final String METHOD_GET = "GET";
+ @Deprecated
+ public static final String METHOD_GET = Method.GET;
public static final String CSRF_REST_NONCE_HEADER_NAME = "X-CSRF-Token";
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/CorsFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/CorsFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/CorsFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/CorsFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -36,6 +36,7 @@
import org.apache.catalina.Globals;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.http.ResponseUtil;
import org.apache.tomcat.util.http.parser.MediaType;
@@ -405,7 +406,7 @@
response.addHeader(RESPONSE_HEADER_ACCESS_CONTROL_EXPOSE_HEADERS, exposedHeadersString);
}
- if ("OPTIONS".equals(method)) {
+ if (Method.OPTIONS.equals(method)) {
// For an OPTIONS request, the response will vary based on the
// value or absence of the following headers. Hence, they need to be
// included in the Vary header.
@@ -546,7 +547,7 @@
if (originHeader.isEmpty() || !RequestUtil.isValidOrigin(originHeader)) {
return CORSRequestType.INVALID_CORS;
}
- if(RequestUtil.isSameOrigin(request, originHeader)) {
+ if (RequestUtil.isSameOrigin(request, originHeader)) {
return CORSRequestType.NOT_CORS;
}
String method = request.getMethod();
@@ -554,8 +555,9 @@
return CORSRequestType.INVALID_CORS;
}
switch (method) {
- case "OPTIONS":
- String accessControlRequestMethodHeader = request.getHeader(REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD);
+ case Method.OPTIONS:
+ String accessControlRequestMethodHeader =
+ request.getHeader(REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD);
if (accessControlRequestMethodHeader != null) {
if (accessControlRequestMethodHeader.isEmpty()) {
return CORSRequestType.INVALID_CORS;
@@ -563,10 +565,10 @@
return CORSRequestType.PRE_FLIGHT;
}
return CORSRequestType.ACTUAL;
- case "GET":
- case "HEAD":
+ case Method.GET:
+ case Method.HEAD:
return CORSRequestType.SIMPLE;
- case "POST":
+ case Method.POST:
String mediaType = MediaType.parseMediaTypeOnly(request.getContentType());
if (mediaType == null || SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES.contains(mediaType)) {
return CORSRequestType.SIMPLE;
@@ -892,7 +894,7 @@
* @see http://www.w3.org/TR/cors/#terminology
*/
public static final Collection SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES =
- Set.of(Globals.CONTENT_TYPE_FORM_URL_ENCODING, "multipart/form-data", "text/plain");
+ Set.of(Globals.CONTENT_TYPE_FORM_URL_ENCODING, "multipart/form-data", "text/plain");
// ------------------------------------------------ Configuration Defaults
/**
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/CsrfPreventionFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/CsrfPreventionFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/CsrfPreventionFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/CsrfPreventionFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -41,6 +41,7 @@
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.Method;
/**
* Provides basic CSRF protection for a web application. The filter assumes that:
@@ -446,7 +447,7 @@
}
protected boolean skipNonceCheck(HttpServletRequest request) {
- if (!Constants.METHOD_GET.equals(request.getMethod())) {
+ if (!Method.GET.equals(request.getMethod())) {
return false;
}
@@ -545,6 +546,8 @@
@Override
public String encodeRedirectURL(String url) {
+ url = removeQueryParameters(url, nonceRequestParameterName);
+
if (shouldAddNonce(url)) {
return addNonce(super.encodeRedirectURL(url));
} else {
@@ -554,6 +557,8 @@
@Override
public String encodeURL(String url) {
+ url = removeQueryParameters(url, nonceRequestParameterName);
+
if (shouldAddNonce(url)) {
return addNonce(super.encodeURL(url));
} else {
@@ -575,6 +580,85 @@
return true;
}
+ /**
+ * Removes zero or more query parameters from a URL. All instances of the query parameter and any associated
+ * values will be removed.
+ *
+ * @param url The URL whose query parameters should be removed.
+ * @param parameterName The name of the parameter to remove.
+ *
+ * @return The URL without any instances of the query parameter parameterName present.
+ */
+ public static String removeQueryParameters(String url, String parameterName) {
+ if (null != parameterName) {
+ // Check for query string
+ int q = url.indexOf('?');
+ if (q > -1) {
+
+ // Look for parameter end
+ int start = q + 1;
+ int pos = url.indexOf('&', start);
+
+ int iterations = 0;
+
+ while (-1 < pos) {
+ // Process all parameters
+ if (++iterations > 100000) {
+ // Just in case things get out of control
+ throw new IllegalStateException("Way too many loop iterations");
+ }
+
+ int eq = url.indexOf('=', start);
+ int paramNameEnd;
+ if (-1 == eq || eq > pos) {
+ paramNameEnd = pos;
+ // Found no equal sign at all or past next & ; Parameter is all name.
+ } else {
+ // Found this param's equal sign
+ paramNameEnd = eq;
+ }
+ if (parameterName.equals(url.substring(start, paramNameEnd))) {
+ // Remove the parameter
+ url = url.substring(0, start) + url.substring(pos + 1); // +1 to consume the &
+ } else {
+ start = pos + 1; // Go to next parameter
+ }
+ pos = url.indexOf('&', start);
+ }
+
+ // Check final parameter
+ String paramName;
+ pos = url.indexOf('=', start);
+
+ if (-1 < pos) {
+ paramName = url.substring(start, pos);
+ } else {
+ paramName = url.substring(start);
+ // No value
+ }
+ if (paramName.equals(parameterName)) {
+ // Remove this parameter
+
+ // Remove any trailing ? or & as well
+ char c = url.charAt(start - 1);
+ if ('?' == c || '&' == c) {
+ start--;
+ }
+
+ url = url.substring(0, start);
+ } else {
+ // Remove trailing ? if it's there. Is this worth it?
+ int length = url.length();
+ if (length == q + 1) {
+ url = url.substring(0, length - 1);
+ }
+ }
+ }
+ }
+
+ return url;
+ }
+
/*
* Return the specified URL with the nonce added to the query string.
*
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/ExpiresFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/ExpiresFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/ExpiresFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/ExpiresFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -44,6 +44,7 @@
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.StringUtils;
+import org.apache.tomcat.util.http.Method;
/**
*
@@ -510,7 +511,7 @@
* ({@link StartingPoint#ACCESS_TIME}) or the last time the HTML-page/servlet-response was modified (
* {@link StartingPoint#LAST_MODIFICATION_TIME}).
*/
- public enum StartingPoint {
+ public enum StartingPoint {
ACCESS_TIME,
LAST_MODIFICATION_TIME
}
@@ -1403,7 +1404,7 @@
// Don't add cache headers unless the request is a GET or a HEAD request
String method = request.getMethod();
- if (!"GET".equals(method) && !"HEAD".equals(method)) {
+ if (!Method.GET.equals(method) && !Method.HEAD.equals(method)) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("expiresFilter.invalidMethod", request.getRequestURI(), method));
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteAddrFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteAddrFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteAddrFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteAddrFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -30,8 +30,9 @@
* Concrete implementation of RequestFilter that filters based on the string representation of the remote
* client's IP address.
*
- * @author Craig R. McClanahan
+ * @deprecated This Filter will be removed in Tomcat 12 onwards. Use {@link RemoteCIDRFilter} instead.
*/
+@Deprecated
public final class RemoteAddrFilter extends RequestFilter {
// Log must be non-static as loggers are created per class-loader and this
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteCIDRFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteCIDRFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteCIDRFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteCIDRFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import jakarta.servlet.FilterChain;
@@ -31,9 +29,9 @@
import jakarta.servlet.http.HttpServletResponse;
import org.apache.catalina.util.NetMask;
+import org.apache.catalina.util.NetMaskSet;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.buf.StringUtils;
public final class RemoteCIDRFilter extends FilterBase {
@@ -49,14 +47,14 @@
private final Log log = LogFactory.getLog(RemoteCIDRFilter.class); // must not be static
/**
- * The list of allowed {@link NetMask}s
+ * The allowed {@link NetMask}s.
*/
- private final List allow = new ArrayList<>();
+ private final NetMaskSet allow = new NetMaskSet();
/**
- * The list of denied {@link NetMask}s
+ * The denied {@link NetMask}s.
*/
- private final List deny = new ArrayList<>();
+ private final NetMaskSet deny = new NetMaskSet();
/**
@@ -77,7 +75,7 @@
* @throws IllegalArgumentException One or more netmasks are invalid
*/
public void setAllow(final String input) {
- final List messages = fillFromInput(input, allow);
+ final List messages = allow.addAll(input);
if (messages.isEmpty()) {
return;
@@ -109,7 +107,7 @@
* @throws IllegalArgumentException One or more netmasks are invalid
*/
public void setDeny(final String input) {
- final List messages = fillFromInput(input, deny);
+ final List messages = deny.addAll(input);
if (messages.isEmpty()) {
return;
@@ -174,22 +172,17 @@
return false;
}
- for (final NetMask nm : deny) {
- if (nm.matches(addr)) {
- return false;
- }
+ if (deny.contains(addr)) {
+ return false;
}
- for (final NetMask nm : allow) {
- if (nm.matches(addr)) {
- return true;
- }
+ if (allow.contains(addr)) {
+ return true;
}
// Allow if deny is specified but allow isn't
// Deny this request otherwise
return !deny.isEmpty() && allow.isEmpty();
-
}
@@ -199,35 +192,4 @@
writer.write(sm.getString("http.403"));
writer.flush();
}
-
-
- /**
- * Fill a {@link NetMask} list from a string input containing a comma-separated list of (hopefully valid)
- * {@link NetMask}s.
- *
- * @param input The input string
- * @param target The list to fill
- *
- * @return a string list of processing errors (empty when no errors)
- */
- private List fillFromInput(final String input, final List target) {
- target.clear();
- if (input == null || input.isEmpty()) {
- return Collections.emptyList();
- }
-
- final List messages = new ArrayList<>();
- NetMask nm;
-
- for (final String s : StringUtils.splitCommaSeparated(input)) {
- try {
- nm = new NetMask(s);
- target.add(nm);
- } catch (IllegalArgumentException e) {
- messages.add(s + ": " + e.getMessage());
- }
- }
-
- return Collections.unmodifiableList(messages);
- }
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteHostFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteHostFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteHostFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteHostFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -28,8 +28,6 @@
/**
* Concrete implementation of RequestFilter that filters based on the remote client's host name.
- *
- * @author Craig R. McClanahan
*/
public final class RemoteHostFilter extends RequestFilter {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteIpFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteIpFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/RemoteIpFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/RemoteIpFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -194,6 +194,7 @@
*
@@ -742,14 +750,13 @@
/**
* @see #setInternalProxies(String)
*/
- private Pattern internalProxies =
- Pattern.compile("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" + "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" +
- "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" + "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" +
- "100\\.6[4-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "100\\.[7-9]{1}\\d{1}\\.\\d{1,3}\\.\\d{1,3}|" +
- "100\\.1[0-1]{1}\\d{1}\\.\\d{1,3}\\.\\d{1,3}|" + "100\\.12[0-7]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
- "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
- "172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "0:0:0:0:0:0:0:1|::1|" +
- "fe[89ab]\\p{XDigit}:.*|" + "f[cd]\\p{XDigit}{2}+:.*");
+ private Pattern internalProxies = Pattern.compile("10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" +
+ "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" + "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" +
+ "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" + "100\\.6[4-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
+ "100\\.[7-9]{1}\\d{1}\\.\\d{1,3}\\.\\d{1,3}|" + "100\\.1[0-1]{1}\\d{1}\\.\\d{1,3}\\.\\d{1,3}|" +
+ "100\\.12[0-7]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
+ "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
+ "0:0:0:0:0:0:0:1|::1|" + "fe[89ab]\\p{XDigit}:.*|" + "f[cd]\\p{XDigit}{2}+:.*");
/**
* @see #setProtocolHeader(String)
@@ -898,7 +905,7 @@
}
} catch (IllegalArgumentException iae) {
- log.debug(sm.getString("remoteIpFilter.invalidHostHeader", hostHeaderValue, hostHeader));
+ log.debug(sm.getString("remoteIpFilter.invalidHostHeader", hostHeaderValue, hostHeader), iae);
}
}
}
@@ -960,7 +967,7 @@
try {
port = Integer.parseInt(portHeaderValue);
} catch (NumberFormatException nfe) {
- log.debug(sm.getString("remoteIpFilter.invalidPort", portHeaderValue, getPortHeader()));
+ log.debug(sm.getString("remoteIpFilter.invalidPort", portHeaderValue, getPortHeader()), nfe);
}
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/filters/RequestDumperFilter.java tomcat10-10.1.52/java/org/apache/catalina/filters/RequestDumperFilter.java
--- tomcat10-10.1.40/java/org/apache/catalina/filters/RequestDumperFilter.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/filters/RequestDumperFilter.java 2026-01-23 19:33:36.000000000 +0000
@@ -46,8 +46,6 @@
* org.apache.catalina.filter.RequestDumperFilter logger is directed to a dedicated file and that the
* org.apache.juli.VerbatimFormatter is used.
*
- *
- * @author Craig R. McClanahan
*/
public class RequestDumperFilter extends GenericFilter {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterListener.java tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* Receive SessionID cluster change from other backup node after primary session node is failed.
- *
- * @author Peter Rossbach
*/
public abstract class ClusterListener implements ChannelListener {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterManager.java tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterManager.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterManager.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterManager.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
/**
* The common interface used by all cluster manager. This is so that we can have a more pluggable way of swapping
* session managers for different algorithms.
- *
- * @author Peter Rossbach
*/
public interface ClusterManager extends Manager {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterRuleSet.java tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterRuleSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterRuleSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterRuleSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,11 +20,7 @@
import org.apache.tomcat.util.digester.RuleSet;
/**
- *
* RuleSet for processing the contents of a Cluster definition element.
- *
- *
- * @author Peter Rossbach
*/
public class ClusterRuleSet implements RuleSet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterValve.java tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/ClusterValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/ClusterValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,8 +21,6 @@
/**
* Cluster valves are a simple extension to the Tomcat valve architecture with a small addition of being able to
* reference the cluster component in the container it sits in.
- *
- * @author Peter Rossbach
*/
public interface ClusterValve extends Valve {
/**
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java tomcat10-10.1.52/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/authenticator/ClusterSingleSignOn.java 2026-01-23 19:33:36.000000000 +0000
@@ -46,8 +46,6 @@
*
The web applications themselves must use one of the standard Authenticators found in the
* org.apache.catalina.authenticator package.
* IMPLEMENTATION NOTE : Correct behavior of session storing and reloading depends upon external calls to the
* start() and stop() methods of this class at the correct times.
- *
- * @author Craig R. McClanahan
- * @author Peter Rossbach
*/
public class DeltaManager extends ClusterManagerBase {
@@ -76,6 +75,7 @@
private int stateTransferTimeout = 60;
private boolean sendAllSessions = true;
private int sendAllSessionsSize = 1000;
+ private boolean enableStatistics = true;
/**
* wait time between send session block (default 2 sec)
@@ -88,25 +88,25 @@
// -------------------------------------------------------- stats attributes
- private volatile long sessionReplaceCounter = 0;
- private volatile long counterReceive_EVT_GET_ALL_SESSIONS = 0;
- private volatile long counterReceive_EVT_ALL_SESSION_DATA = 0;
- private volatile long counterReceive_EVT_SESSION_CREATED = 0;
- private volatile long counterReceive_EVT_SESSION_EXPIRED = 0;
- private volatile long counterReceive_EVT_SESSION_ACCESSED = 0;
- private volatile long counterReceive_EVT_SESSION_DELTA = 0;
- private volatile int counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
- private volatile long counterReceive_EVT_CHANGE_SESSION_ID = 0;
- private volatile long counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER = 0;
- private volatile long counterSend_EVT_GET_ALL_SESSIONS = 0;
- private volatile long counterSend_EVT_ALL_SESSION_DATA = 0;
- private volatile long counterSend_EVT_SESSION_CREATED = 0;
- private volatile long counterSend_EVT_SESSION_DELTA = 0;
- private volatile long counterSend_EVT_SESSION_ACCESSED = 0;
- private volatile long counterSend_EVT_SESSION_EXPIRED = 0;
- private volatile int counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
- private volatile long counterSend_EVT_CHANGE_SESSION_ID = 0;
- private volatile int counterNoStateTransferred = 0;
+ private final AtomicLong sessionReplaceCounter = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_GET_ALL_SESSIONS = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_ALL_SESSION_DATA = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_SESSION_CREATED = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_SESSION_EXPIRED = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_SESSION_ACCESSED = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_SESSION_DELTA = new AtomicLong(0);
+ private final AtomicInteger counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = new AtomicInteger(0);
+ private final AtomicLong counterReceive_EVT_CHANGE_SESSION_ID = new AtomicLong(0);
+ private final AtomicLong counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER = new AtomicLong(0);
+ private final AtomicLong counterSend_EVT_GET_ALL_SESSIONS = new AtomicLong(0);
+ private final AtomicLong counterSend_EVT_ALL_SESSION_DATA = new AtomicLong(0);
+ private final AtomicLong counterSend_EVT_SESSION_CREATED = new AtomicLong(0);
+ private final AtomicLong counterSend_EVT_SESSION_DELTA = new AtomicLong(0);
+ private final AtomicLong counterSend_EVT_SESSION_ACCESSED = new AtomicLong(0);
+ private final AtomicLong counterSend_EVT_SESSION_EXPIRED = new AtomicLong(0);
+ private final AtomicInteger counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = new AtomicInteger(0);
+ private final AtomicLong counterSend_EVT_CHANGE_SESSION_ID = new AtomicLong(0);
+ private final AtomicInteger counterNoStateTransferred = new AtomicInteger(0);
// ------------------------------------------------------------- Constructor
@@ -130,98 +130,98 @@
* @return Returns the counterSend_EVT_GET_ALL_SESSIONS.
*/
public long getCounterSend_EVT_GET_ALL_SESSIONS() {
- return counterSend_EVT_GET_ALL_SESSIONS;
+ return counterSend_EVT_GET_ALL_SESSIONS.get();
}
/**
* @return Returns the counterSend_EVT_SESSION_ACCESSED.
*/
public long getCounterSend_EVT_SESSION_ACCESSED() {
- return counterSend_EVT_SESSION_ACCESSED;
+ return counterSend_EVT_SESSION_ACCESSED.get();
}
/**
* @return Returns the counterSend_EVT_SESSION_CREATED.
*/
public long getCounterSend_EVT_SESSION_CREATED() {
- return counterSend_EVT_SESSION_CREATED;
+ return counterSend_EVT_SESSION_CREATED.get();
}
/**
* @return Returns the counterSend_EVT_SESSION_DELTA.
*/
public long getCounterSend_EVT_SESSION_DELTA() {
- return counterSend_EVT_SESSION_DELTA;
+ return counterSend_EVT_SESSION_DELTA.get();
}
/**
* @return Returns the counterSend_EVT_SESSION_EXPIRED.
*/
public long getCounterSend_EVT_SESSION_EXPIRED() {
- return counterSend_EVT_SESSION_EXPIRED;
+ return counterSend_EVT_SESSION_EXPIRED.get();
}
/**
* @return Returns the counterSend_EVT_ALL_SESSION_DATA.
*/
public long getCounterSend_EVT_ALL_SESSION_DATA() {
- return counterSend_EVT_ALL_SESSION_DATA;
+ return counterSend_EVT_ALL_SESSION_DATA.get();
}
/**
* @return Returns the counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE.
*/
public int getCounterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE() {
- return counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE;
+ return counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE.get();
}
/**
* @return Returns the counterSend_EVT_CHANGE_SESSION_ID.
*/
public long getCounterSend_EVT_CHANGE_SESSION_ID() {
- return counterSend_EVT_CHANGE_SESSION_ID;
+ return counterSend_EVT_CHANGE_SESSION_ID.get();
}
/**
* @return Returns the counterReceive_EVT_ALL_SESSION_DATA.
*/
public long getCounterReceive_EVT_ALL_SESSION_DATA() {
- return counterReceive_EVT_ALL_SESSION_DATA;
+ return counterReceive_EVT_ALL_SESSION_DATA.get();
}
/**
* @return Returns the counterReceive_EVT_GET_ALL_SESSIONS.
*/
public long getCounterReceive_EVT_GET_ALL_SESSIONS() {
- return counterReceive_EVT_GET_ALL_SESSIONS;
+ return counterReceive_EVT_GET_ALL_SESSIONS.get();
}
/**
* @return Returns the counterReceive_EVT_SESSION_ACCESSED.
*/
public long getCounterReceive_EVT_SESSION_ACCESSED() {
- return counterReceive_EVT_SESSION_ACCESSED;
+ return counterReceive_EVT_SESSION_ACCESSED.get();
}
/**
* @return Returns the counterReceive_EVT_SESSION_CREATED.
*/
public long getCounterReceive_EVT_SESSION_CREATED() {
- return counterReceive_EVT_SESSION_CREATED;
+ return counterReceive_EVT_SESSION_CREATED.get();
}
/**
* @return Returns the counterReceive_EVT_SESSION_DELTA.
*/
public long getCounterReceive_EVT_SESSION_DELTA() {
- return counterReceive_EVT_SESSION_DELTA;
+ return counterReceive_EVT_SESSION_DELTA.get();
}
/**
* @return Returns the counterReceive_EVT_SESSION_EXPIRED.
*/
public long getCounterReceive_EVT_SESSION_EXPIRED() {
- return counterReceive_EVT_SESSION_EXPIRED;
+ return counterReceive_EVT_SESSION_EXPIRED.get();
}
@@ -229,35 +229,35 @@
* @return Returns the counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE.
*/
public int getCounterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE() {
- return counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE;
+ return counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE.get();
}
/**
* @return Returns the counterReceive_EVT_CHANGE_SESSION_ID.
*/
public long getCounterReceive_EVT_CHANGE_SESSION_ID() {
- return counterReceive_EVT_CHANGE_SESSION_ID;
+ return counterReceive_EVT_CHANGE_SESSION_ID.get();
}
/**
* @return Returns the counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER.
*/
public long getCounterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER() {
- return counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER;
+ return counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER.get();
}
/**
* @return Returns the sessionReplaceCounter.
*/
public long getSessionReplaceCounter() {
- return sessionReplaceCounter;
+ return sessionReplaceCounter.get();
}
/**
* @return Returns the counterNoStateTransferred.
*/
public int getCounterNoStateTransferred() {
- return counterNoStateTransferred;
+ return counterNoStateTransferred.get();
}
public int getReceivedQueueSize() {
@@ -391,6 +391,19 @@
this.notifyContainerListenersOnReplication = notifyContainerListenersOnReplication;
}
+ /**
+ * @return the enableStatistics
+ */
+ public boolean getEnableStatistics() {
+ return this.enableStatistics;
+ }
+
+ /**
+ * @param enableStatistics the enableStatistics to set
+ */
+ public void setEnableStatistics(boolean enableStatistics) {
+ this.enableStatistics = enableStatistics;
+ }
// --------------------------------------------------------- Public Methods
@@ -433,7 +446,9 @@
log.trace(sm.getString("deltaManager.sendMessage.newSession", name, sessionId));
}
msg.setTimestamp(session.getCreationTime());
- counterSend_EVT_SESSION_CREATED++;
+ if (enableStatistics) {
+ counterSend_EVT_SESSION_CREATED.incrementAndGet();
+ }
send(msg);
}
}
@@ -495,10 +510,12 @@
SessionMessage msg = new SessionMessageImpl(getName(), SessionMessage.EVT_CHANGE_SESSION_ID, data,
orgSessionID, orgSessionID + "-" + System.currentTimeMillis());
msg.setTimestamp(System.currentTimeMillis());
- counterSend_EVT_CHANGE_SESSION_ID++;
+ if (enableStatistics) {
+ counterSend_EVT_CHANGE_SESSION_ID.incrementAndGet();
+ }
send(msg);
- } catch (IOException e) {
- log.error(sm.getString("deltaManager.unableSerializeSessionID", newSessionID), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("deltaManager.unableSerializeSessionID", newSessionID), ioe);
}
}
}
@@ -573,7 +590,9 @@
session.resetDeltaRequest();
// FIXME How inform other session id cache like SingleSignOn
if (findSession(session.getIdInternal()) != null) {
- sessionReplaceCounter++;
+ if (enableStatistics) {
+ sessionReplaceCounter.incrementAndGet();
+ }
// FIXME better is to grap this sessions again !
if (log.isWarnEnabled()) {
log.warn(sm.getString("deltaManager.loading.existing.session", session.getIdInternal()));
@@ -587,9 +606,9 @@
} catch (ClassNotFoundException e) {
log.error(sm.getString("deltaManager.loading.cnfe", e), e);
throw e;
- } catch (IOException e) {
- log.error(sm.getString("deltaManager.loading.ioe", e), e);
- throw e;
+ } catch (IOException ioe) {
+ log.error(sm.getString("deltaManager.loading.ioe", ioe), ioe);
+ throw ioe;
}
}
@@ -615,9 +634,9 @@
}
// Flush and close the output stream
oos.flush();
- } catch (IOException e) {
- log.error(sm.getString("deltaManager.unloading.ioe", e), e);
- throw e;
+ } catch (IOException ioe) {
+ log.error(sm.getString("deltaManager.unloading.ioe", ioe), ioe);
+ throw ioe;
}
// send object data as byte[]
@@ -684,7 +703,9 @@
// set reference time
stateTransferCreateSendTime = beforeSendTime;
// request session state
- counterSend_EVT_GET_ALL_SESSIONS++;
+ if (enableStatistics) {
+ counterSend_EVT_GET_ALL_SESSIONS.incrementAndGet();
+ }
stateTransferred = false;
// FIXME This send call block the deploy thread, when sender waitForAck is enabled
try {
@@ -764,8 +785,8 @@
do {
try {
Thread.sleep(100);
- } catch (Exception sleep) {
- //
+ } catch (Exception ignore) {
+ // Ignore
}
reqNow = System.currentTimeMillis();
isTimeout = ((reqNow - reqStart) > (1000L * getStateTransferTimeout()));
@@ -776,7 +797,7 @@
do {
try {
Thread.sleep(100);
- } catch (Exception sleep) {
+ } catch (Exception ignore) {
// Ignore
}
} while ((!getStateTransferred()) && (!isNoContextManagerReceived()));
@@ -784,7 +805,9 @@
}
}
if (isTimeout) {
- counterNoStateTransferred++;
+ if (enableStatistics) {
+ counterNoStateTransferred.incrementAndGet();
+ }
log.error(sm.getString("deltaManager.noSessionState", getName(), new Date(beforeSendTime),
Long.valueOf(reqNow - beforeSendTime)));
} else if (isNoContextManagerReceived()) {
@@ -894,17 +917,21 @@
return null;
}
if (session.isDirty()) {
- counterSend_EVT_SESSION_DELTA++;
+ if (enableStatistics) {
+ counterSend_EVT_SESSION_DELTA.incrementAndGet();
+ }
msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_DELTA, session.getDiff(), sessionId,
sessionId + "-" + System.currentTimeMillis());
}
- } catch (IOException x) {
- log.error(sm.getString("deltaManager.createMessage.unableCreateDeltaRequest", sessionId), x);
+ } catch (IOException ioe) {
+ log.error(sm.getString("deltaManager.createMessage.unableCreateDeltaRequest", sessionId), ioe);
return null;
}
if (msg == null) {
if (!expires && !session.isPrimarySession()) {
- counterSend_EVT_SESSION_ACCESSED++;
+ if (enableStatistics) {
+ counterSend_EVT_SESSION_ACCESSED.incrementAndGet();
+ }
msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_ACCESSED, null, sessionId,
sessionId + "-" + System.currentTimeMillis());
if (log.isDebugEnabled()) {
@@ -923,7 +950,9 @@
if (!expires && (msg == null)) {
long replDelta = System.currentTimeMillis() - session.getLastTimeReplicated();
if (session.getMaxInactiveInterval() >= 0 && replDelta > (session.getMaxInactiveInterval() * 1000L)) {
- counterSend_EVT_SESSION_ACCESSED++;
+ if (enableStatistics) {
+ counterSend_EVT_SESSION_ACCESSED.incrementAndGet();
+ }
msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_ACCESSED, null, sessionId,
sessionId + "-" + System.currentTimeMillis());
if (log.isDebugEnabled()) {
@@ -959,25 +988,25 @@
}
}
rejectedSessions = 0;
- sessionReplaceCounter = 0;
- counterNoStateTransferred = 0;
+ sessionReplaceCounter.set(0);
+ counterNoStateTransferred.set(0);
setMaxActive(getActiveSessions());
- counterReceive_EVT_ALL_SESSION_DATA = 0;
- counterReceive_EVT_GET_ALL_SESSIONS = 0;
- counterReceive_EVT_SESSION_ACCESSED = 0;
- counterReceive_EVT_SESSION_CREATED = 0;
- counterReceive_EVT_SESSION_DELTA = 0;
- counterReceive_EVT_SESSION_EXPIRED = 0;
- counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
- counterReceive_EVT_CHANGE_SESSION_ID = 0;
- counterSend_EVT_ALL_SESSION_DATA = 0;
- counterSend_EVT_GET_ALL_SESSIONS = 0;
- counterSend_EVT_SESSION_ACCESSED = 0;
- counterSend_EVT_SESSION_CREATED = 0;
- counterSend_EVT_SESSION_DELTA = 0;
- counterSend_EVT_SESSION_EXPIRED = 0;
- counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
- counterSend_EVT_CHANGE_SESSION_ID = 0;
+ counterReceive_EVT_ALL_SESSION_DATA.set(0);
+ counterReceive_EVT_GET_ALL_SESSIONS.set(0);
+ counterReceive_EVT_SESSION_ACCESSED.set(0);
+ counterReceive_EVT_SESSION_CREATED.set(0);
+ counterReceive_EVT_SESSION_DELTA.set(0);
+ counterReceive_EVT_SESSION_EXPIRED.set(0);
+ counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE.set(0);
+ counterReceive_EVT_CHANGE_SESSION_ID.set(0);
+ counterSend_EVT_ALL_SESSION_DATA.set(0);
+ counterSend_EVT_GET_ALL_SESSIONS.set(0);
+ counterSend_EVT_SESSION_ACCESSED.set(0);
+ counterSend_EVT_SESSION_CREATED.set(0);
+ counterSend_EVT_SESSION_DELTA.set(0);
+ counterSend_EVT_SESSION_EXPIRED.set(0);
+ counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE.set(0);
+ counterSend_EVT_CHANGE_SESSION_ID.set(0);
}
@@ -990,7 +1019,9 @@
*/
protected void sessionExpired(String id) {
if (cluster.getMembers().length > 0) {
- counterSend_EVT_SESSION_EXPIRED++;
+ if (enableStatistics) {
+ counterSend_EVT_SESSION_EXPIRED.incrementAndGet();
+ }
SessionMessage msg = new SessionMessageImpl(getName(), SessionMessage.EVT_SESSION_EXPIRED, null, id,
id + "-EXPIRED-MSG");
msg.setTimestamp(System.currentTimeMillis());
@@ -1093,8 +1124,8 @@
// we didn't recognize the message type, do nothing
break;
} // switch
- } catch (Exception x) {
- log.error(sm.getString("deltaManager.receiveMessage.error", getName()), x);
+ } catch (Exception e) {
+ log.error(sm.getString("deltaManager.receiveMessage.error", getName()), e);
} finally {
currentThread.setContextClassLoader(contextLoader);
}
@@ -1110,7 +1141,9 @@
* @param sender Member which sent the message
*/
protected void handleALL_SESSION_TRANSFERCOMPLETE(SessionMessage msg, Member sender) {
- counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE++;
+ if (enableStatistics) {
+ counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE.incrementAndGet();
+ }
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.receiveMessage.transfercomplete", getName(), sender.getHost(),
Integer.valueOf(sender.getPort())));
@@ -1129,7 +1162,9 @@
* @throws ClassNotFoundException Serialization error
*/
protected void handleSESSION_DELTA(SessionMessage msg, Member sender) throws IOException, ClassNotFoundException {
- counterReceive_EVT_SESSION_DELTA++;
+ if (enableStatistics) {
+ counterReceive_EVT_SESSION_DELTA.incrementAndGet();
+ }
byte[] delta = msg.getSession();
DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
if (session == null) {
@@ -1154,7 +1189,9 @@
* @throws IOException Propagated IO error
*/
protected void handleSESSION_ACCESSED(SessionMessage msg, Member sender) throws IOException {
- counterReceive_EVT_SESSION_ACCESSED++;
+ if (enableStatistics) {
+ counterReceive_EVT_SESSION_ACCESSED.incrementAndGet();
+ }
DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
if (session != null) {
if (log.isDebugEnabled()) {
@@ -1175,7 +1212,9 @@
* @throws IOException Propagated IO error
*/
protected void handleSESSION_EXPIRED(SessionMessage msg, Member sender) throws IOException {
- counterReceive_EVT_SESSION_EXPIRED++;
+ if (enableStatistics) {
+ counterReceive_EVT_SESSION_EXPIRED.incrementAndGet();
+ }
DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
if (session != null) {
if (log.isDebugEnabled()) {
@@ -1192,7 +1231,9 @@
* @param sender Member which sent the message
*/
protected void handleSESSION_CREATED(SessionMessage msg, Member sender) {
- counterReceive_EVT_SESSION_CREATED++;
+ if (enableStatistics) {
+ counterReceive_EVT_SESSION_CREATED.incrementAndGet();
+ }
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.receiveMessage.createNewSession", getName(), msg.getSessionID()));
}
@@ -1220,7 +1261,9 @@
*/
protected void handleALL_SESSION_DATA(SessionMessage msg, Member sender)
throws ClassNotFoundException, IOException {
- counterReceive_EVT_ALL_SESSION_DATA++;
+ if (enableStatistics) {
+ counterReceive_EVT_ALL_SESSION_DATA.incrementAndGet();
+ }
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataBegin", getName()));
}
@@ -1242,7 +1285,9 @@
* @throws IOException IO error sending messages
*/
protected void handleGET_ALL_SESSIONS(SessionMessage msg, Member sender) throws IOException {
- counterReceive_EVT_GET_ALL_SESSIONS++;
+ if (enableStatistics) {
+ counterReceive_EVT_GET_ALL_SESSIONS.incrementAndGet();
+ }
// get a list of all the session from this manager
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.receiveMessage.unloadingBegin", getName()));
@@ -1266,7 +1311,7 @@
if (getSendAllSessionsWaitTime() > 0 && remain > 0) {
try {
Thread.sleep(getSendAllSessionsWaitTime());
- } catch (Exception sleep) {
+ } catch (Exception ignore) {
// Ignore
}
}
@@ -1279,7 +1324,9 @@
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.createMessage.allSessionTransferred", getName()));
}
- counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE++;
+ if (enableStatistics) {
+ counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE.incrementAndGet();
+ }
cluster.send(newmsg, sender);
}
@@ -1292,7 +1339,9 @@
* @throws IOException IO error with serialization
*/
protected void handleCHANGE_SESSION_ID(SessionMessage msg, Member sender) throws IOException {
- counterReceive_EVT_CHANGE_SESSION_ID++;
+ if (enableStatistics) {
+ counterReceive_EVT_CHANGE_SESSION_ID.incrementAndGet();
+ }
DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
if (session != null) {
String newSessionID = deserializeSessionId(msg.getSession());
@@ -1310,7 +1359,9 @@
* @param sender Member which sent the message
*/
protected void handleALL_SESSION_NOCONTEXTMANAGER(SessionMessage msg, Member sender) {
- counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER++;
+ if (enableStatistics) {
+ counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER.incrementAndGet();
+ }
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.receiveMessage.noContextManager", getName(), sender.getHost(),
Integer.valueOf(sender.getPort())));
@@ -1338,7 +1389,9 @@
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.createMessage.allSessionData", getName()));
}
- counterSend_EVT_ALL_SESSION_DATA++;
+ if (enableStatistics) {
+ counterSend_EVT_ALL_SESSION_DATA.incrementAndGet();
+ }
int sendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK | Channel.SEND_OPTIONS_USE_ACK;
cluster.send(newmsg, sender, sendOptions);
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/session/DeltaRequest.java tomcat10-10.1.52/java/org/apache/catalina/ha/session/DeltaRequest.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/session/DeltaRequest.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/session/DeltaRequest.java 2026-01-23 19:33:36.000000000 +0000
@@ -147,8 +147,8 @@
if (!this.actionPool.isEmpty()) {
try {
info = actionPool.removeFirst();
- } catch (Exception x) {
- log.error(sm.getString("deltaRequest.removeUnable"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("deltaRequest.removeUnable"), e);
info = new AttributeInfo(type, action, name, value);
}
info.init(type, action, name, value);
@@ -251,8 +251,8 @@
AttributeInfo info = actions.removeFirst();
info.recycle();
actionPool.addLast(info);
- } catch (Exception x) {
- log.error(sm.getString("deltaRequest.removeUnable"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("deltaRequest.removeUnable"), e);
}
}
}
@@ -264,8 +264,8 @@
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
if (sessionId == null) {
- Exception e = new Exception(sm.getString("deltaRequest.ssid.null"));
- log.error(sm.getString("deltaRequest.ssid.null"), e.fillInStackTrace());
+ String msg = sm.getString("deltaRequest.ssid.null");
+ log.error(msg, new Exception(msg));
}
}
@@ -293,8 +293,8 @@
if (!this.actionPool.isEmpty()) {
try {
info = actionPool.removeFirst();
- } catch (Exception x) {
- log.error(sm.getString("deltaRequest.removeUnable"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("deltaRequest.removeUnable"), e);
info = new AttributeInfo();
}
} else {
@@ -431,9 +431,8 @@
@Override
public String toString() {
- return "AttributeInfo[type=" + getType() + ", action=" + getAction() +
- ", name=" + getName() + ", value=" + getValue() +
- ", addr=" + super.toString() + ']';
+ return "AttributeInfo[type=" + getType() + ", action=" + getAction() + ", name=" + getName() + ", value=" +
+ getValue() + ", addr=" + super.toString() + ']';
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/session/JvmRouteBinderValve.java tomcat10-10.1.52/java/org/apache/catalina/ha/session/JvmRouteBinderValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/session/JvmRouteBinderValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/session/JvmRouteBinderValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -58,8 +58,6 @@
* You can enable this mod_jk turnover mode via JMX before you drop a node to all backup nodes! Set enable true on all
* JvmRouteBinderValve backups, disable worker at mod_jk and then drop node and restart it! Then enable mod_jk worker
* and disable JvmRouteBinderValves again. This use case means that only requested sessions are migrated.
- *
- * @author Peter Rossbach
*/
public class JvmRouteBinderValve extends ValveBase implements ClusterValve {
@@ -258,8 +256,8 @@
Session catalinaSession = null;
try {
catalinaSession = getManager(request).findSession(sessionId);
- } catch (IOException e) {
- // Hups!
+ } catch (IOException ignore) {
+ // Error looking for session using old session ID. Treat it as not found.
}
String id = sessionId.substring(0, index);
String newSessionID = id + "." + localJvmRoute;
@@ -270,11 +268,11 @@
} else {
try {
catalinaSession = getManager(request).findSession(newSessionID);
- } catch (IOException e) {
- // Hups!
+ } catch (IOException ignore) {
+ // Error looking for session using new session ID. Treat it as not found.
}
if (catalinaSession != null) {
- // session is rewrite at other request, rewrite this also
+ // Session was rewritten in other, concurrent request. Rewrite this request also.
changeRequestSessionID(request, sessionId, newSessionID);
} else {
if (log.isDebugEnabled()) {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/session/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/ha/session/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/ha/session/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/session/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -82,7 +82,7 @@
jvmRoute.changeSession=セッションを [{0}] から [{1}] へ変更しました。
jvmRoute.failover=他の jvmRoute へのフェールオーバーを検出しました。元のルートは [{0}]、新しいルートは [{1}]、セッション ID は [{2}] です。
jvmRoute.foundManager=Cluster Manager [{0}] を [{1}] で発見しました
-jvmRoute.missingJvmRouteAttribute=jvmRoute 属性にエンジンが指定されていません。
+jvmRoute.missingJvmRouteAttribute=Engine に jvmRoute 属性が指定されていません!
jvmRoute.noCluster=JvmRouterBinderValveは設定されていますが、クラスタリングは使用されていません。 PersistentManagerが使用されている場合、フェールオーバーは引き続き機能します。
jvmRoute.notFoundManager=[{0}]でCluster Managerが見つかりません。
jvmRoute.set.originalsessionid=オリジナルSession idをリクエスト属性[{0}]の値:[{1}]で設定します。
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/session/SessionMessage.java tomcat10-10.1.52/java/org/apache/catalina/ha/session/SessionMessage.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/session/SessionMessage.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/session/SessionMessage.java 2026-01-23 19:33:36.000000000 +0000
@@ -47,8 +47,8 @@
int EVT_SESSION_EXPIRED = 2;
/**
- * Event type used when a session has been accessed (ie, last access time has been updated). This is used so that the
- * replicated sessions will not expire on the network
+ * Event type used when a session has been accessed (ie, last access time has been updated). This is used so that
+ * the replicated sessions will not expire on the network
*/
int EVT_SESSION_ACCESSED = 3;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/session/SessionMessageImpl.java tomcat10-10.1.52/java/org/apache/catalina/ha/session/SessionMessageImpl.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/session/SessionMessageImpl.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/session/SessionMessageImpl.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,9 +20,7 @@
import org.apache.catalina.ha.ClusterMessageBase;
/**
- * Session cluster message
- *
- * @author Peter Rossbach
+ * Session cluster message.
*/
public class SessionMessageImpl extends ClusterMessageBase implements SessionMessage {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/Constants.java tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/Constants.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/Constants.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/Constants.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,8 +18,6 @@
/**
* Manifest constants for the org.apache.catalina.ha.tcp package.
- *
- * @author Peter Rossbach
*/
public class Constants {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/ReplicationValve.java tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/ReplicationValve.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/ReplicationValve.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/ReplicationValve.java 2026-01-23 19:33:36.000000000 +0000
@@ -47,21 +47,14 @@
import org.apache.tomcat.util.res.StringManager;
/**
- *
* Implementation of a Valve that logs interesting contents from the specified Request (before processing) and the
* corresponding Response (after processing). It is especially useful in debugging problems related to headers and
* cookies.
- *
*
* This Valve may be attached to any Container, depending on the granularity of the logging you wish to perform.
- *
*
* primaryIndicator=true, then the request attribute org.apache.catalina.ha.tcp.isPrimarySession. is set true,
* when request processing is at sessions primary node.
- *
- *
- * @author Craig R. McClanahan
- * @author Peter Rossbach
*/
public class ReplicationValve extends ValveBase implements ClusterValve {
@@ -377,9 +370,9 @@
if (isCrossContext) {
sendCrossContextSession();
}
- } catch (Exception x) {
+ } catch (Exception e) {
// FIXME we have a lot of sends, but the trouble with one node stops the correct replication to other nodes!
- log.error(sm.getString("ReplicationValve.send.failure"), x);
+ log.error(sm.getString("ReplicationValve.send.failure"), e);
} finally {
if (doStatistics()) {
updateStats(totalstart, start, isAsync);
@@ -506,8 +499,8 @@
for (String invalidId : invalidIds) {
try {
send(manager, invalidId);
- } catch (Exception x) {
- log.error(sm.getString("ReplicationValve.send.invalid.failure", invalidId), x);
+ } catch (Exception e) {
+ log.error(sm.getString("ReplicationValve.send.invalid.failure", invalidId), e);
}
}
}
@@ -545,8 +538,7 @@
Long.valueOf(totalSendTime.longValue() / nrOfRequests.longValue()),
Long.valueOf(nrOfRequests.longValue()), Long.valueOf(nrOfSendRequests.longValue()),
Long.valueOf(nrOfCrossContextSendRequests.longValue()),
- Long.valueOf(nrOfFilterRequests.longValue()),
- Long.valueOf(totalRequestTime.longValue()),
+ Long.valueOf(nrOfFilterRequests.longValue()), Long.valueOf(totalRequestTime.longValue()),
Long.valueOf(totalSendTime.longValue())));
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/SendMessageData.java tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/SendMessageData.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/SendMessageData.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/SendMessageData.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,9 +18,6 @@
import org.apache.catalina.tribes.Member;
-/**
- * @author Peter Rossbach
- */
public class SendMessageData {
private Object message;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
--- tomcat10-10.1.40/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java 2026-01-23 19:33:36.000000000 +0000
@@ -59,9 +59,6 @@
/**
* A Cluster implementation using simple multicast. Responsible for setting up a cluster and provides callers
* with a valid multicast receiver/sender.
- *
- * @author Remy Maucherat
- * @author Peter Rossbach
*/
public class SimpleTcpCluster extends LifecycleMBeanBase
implements CatalinaCluster, MembershipListener, ChannelListener {
@@ -345,8 +342,8 @@
try {
manager = managerTemplate.cloneFromTemplate();
manager.setName(name);
- } catch (Exception x) {
- log.error(sm.getString("simpleTcpCluster.clustermanager.cloneFailed"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("simpleTcpCluster.clustermanager.cloneFailed"), e);
manager = new DeltaManager();
} finally {
if (manager != null) {
@@ -470,9 +467,9 @@
clusterDeployer.start();
}
registerMember(channel.getLocalMember(false));
- } catch (Exception x) {
- log.error(sm.getString("simpleTcpCluster.startUnable"), x);
- throw new LifecycleException(x);
+ } catch (Exception e) {
+ log.error(sm.getString("simpleTcpCluster.startUnable"), e);
+ throw new LifecycleException(e);
}
setState(LifecycleState.STARTING);
@@ -560,8 +557,8 @@
channel.removeChannelListener(this);
channel.removeMembershipListener(this);
this.unregisterClusterValve();
- } catch (Exception x) {
- log.error(sm.getString("simpleTcpCluster.stopUnable"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("simpleTcpCluster.stopUnable"), e);
}
channel.setUtilityExecutor(null);
@@ -612,8 +609,8 @@
log.debug(sm.getString("simpleTcpCluster.noMembers", msg));
}
}
- } catch (Exception x) {
- log.error(sm.getString("simpleTcpCluster.sendFailed"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("simpleTcpCluster.sendFailed"), e);
}
}
@@ -631,8 +628,8 @@
// Notify our interested LifecycleListeners
fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member);
- } catch (Exception x) {
- log.error(sm.getString("simpleTcpCluster.member.addFailed"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("simpleTcpCluster.member.addFailed"), e);
}
}
@@ -651,8 +648,8 @@
// Notify our interested LifecycleListeners
fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member);
- } catch (Exception x) {
- log.error(sm.getString("simpleTcpCluster.member.removeFailed"), x);
+ } catch (Exception e) {
+ log.error(sm.getString("simpleTcpCluster.member.removeFailed"), e);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings.properties tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -50,7 +50,7 @@
webappClassLoader.restrictedPackage=Security violation, attempt to use restricted class [{0}]
webappClassLoader.securityException=Security exception trying to find class [{0}] in findClassInternal [{1}]
webappClassLoader.stackTrace=The web application [{0}] appears to have started a thread named [{1}] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:{2}
-webappClassLoader.stackTraceRequestThread=The web application [{0}] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation. Stack trace of request processing thread:[{2}]
+webappClassLoader.stackTraceRequestThread=The thread [{1}] of web application [{0}] is still processing a request that has yet to finish. This is very likely to create a memory leak. You can control the time allowed for requests to finish by using the unloadDelay attribute of the standard Context implementation. Stack trace of request processing thread:[{2}]
webappClassLoader.stopThreadFail=Failed to terminate thread named [{0}] for web application [{1}]
webappClassLoader.stopTimerThreadFail=Failed to terminate TimerThread named [{0}] for web application [{1}]
webappClassLoader.stopped=Illegal access: this web application instance has been stopped already. Could not load [{0}]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_fr.properties tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_fr.properties
--- tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_fr.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_fr.properties 2026-01-23 19:33:36.000000000 +0000
@@ -50,7 +50,7 @@
webappClassLoader.restrictedPackage=Violation de sécurité en essayant d''utiliser à une classe à accès restreint [{0}]
webappClassLoader.securityException=Exception de sécurité en essayant de trouver la classe [{0}] dans findClassInternal [{1}]
webappClassLoader.stackTrace=L''application web [{0}] semble avoir démarré un thread nommé [{1}] mais ne l''a pas arrêté, ce qui va probablement créer une fuite de mémoire ; la trace du thread est : {2}
-webappClassLoader.stackTraceRequestThread=Une requête de l''application web [{0}] est toujours en cours, ce qui causera certainement une fuite de mémoire, vous pouvez contrôler le temps alloué en utilisant l''attribut unloadDelay de l''implémentation standard de Context ; trace du fil d’exécution de la requête : [{2}]
+webappClassLoader.stackTraceRequestThread=Le thread [{1}] de l''application web [{0}] est toujours en cours, ce qui risque de causer une fuite de mémoire. Vous pouvez contrôler le temps alloué en utilisant l''attribut unloadDelay de l''implémentation standard de Context ; trace de la pile d''exécution de la requête : [{2}]
webappClassLoader.stopThreadFail=Impossible de terminer le thread nommé [{0}] pour l''application [{1}]
webappClassLoader.stopTimerThreadFail=Echec de l''arrêt du TimerThread nommé [{0}] pour l''application web [{1}]
webappClassLoader.stopped=Impossible de charger [{0}], ce chargeur de classes a déjà été arrêté
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -50,7 +50,7 @@
webappClassLoader.restrictedPackage=セキュリティー違反。制限されたクラス [{0}] を使おうとしました。
webappClassLoader.securityException=indClassInternal [{1}] でクラス [{0}] を検索中のセキュリティ例外です
webappClassLoader.stackTrace=Webアプリケーション [{0}] は [{1}] という名前のスレッドを開始したようですが、停止に失敗しました。これはメモリリークを引き起こす可能性が非常に高いです。スレッドのスタックトレース: {2}
-webappClassLoader.stackTraceRequestThread=Webアプリケーション[{0}]はまだ完了していないリクエストを処理しています。 これはメモリリークを引き起こす可能性が非常に高いです。 リクエストの終了時間は、StandardContext実装のunloadDelay属性を使用して制御できます。 リクエスト処理スレッドのスタックトレース:[{2}]
+webappClassLoader.stackTraceRequestThread=Webアプリケーション[{0}]のスレッド[{1}]はまだ完了していないリクエストを処理しています。 これはメモリリークを引き起こす可能性が非常に高いです。 リクエストの終了時間は、StandardContext実装のunloadDelay属性を使用して制御できます。 リクエスト処理スレッドのスタックトレース:[{2}]
webappClassLoader.stopThreadFail=Web アプリケーション [{1}] のスレッド [{0}] は終了できません。
webappClassLoader.stopTimerThreadFail=Webアプリケーション [{1}] の [{0}] という名前のTimerThreadを終了できませんでした
webappClassLoader.stopped=不正なアクセス: このWebアプリケーションのインスタンスは既に停止されています Could not load [{0}]. 不正なアクセスを引き起こしたスレッドを終了させ、投げられたエラーによりデバッグ用に次のスタックトレースが生成されましたが,機能に影響はありません
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_ko.properties tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_ko.properties
--- tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_ko.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_ko.properties 2026-01-23 19:33:36.000000000 +0000
@@ -50,7 +50,7 @@
webappClassLoader.restrictedPackage=보안 위반 행위: 제한된 클래스 [{0}]을(를) 사용하려 시도했습니다.
webappClassLoader.securityException=findClassInternal에서, 클래스 [{0}]을(를) 찾으려 시도 중 보안 예외 발생: [{1}]
webappClassLoader.stackTrace=웹 애플리케이션 [{0}]이(가) [{1}](이)라는 이름의 쓰레드를 시작시킨 것으로 보이지만, 해당 쓰레드를 중지시키지 못했습니다. 이는 메모리 누수를 유발할 가능성이 큽니다. 해당 쓰레드의 스택 트레이스:{2}
-webappClassLoader.stackTraceRequestThread=웹 애플리케이션 [{0}]이(가) 여전히 완료되지 않은 요청을 처리하고 있습니다. 이는 메모리 누수를 유발할 가능성이 높습니다. 표준 컨텍스트 구현의 unloadDelay 속성을 이용하여, 요청 완료 허용 시간을 통제할 수 있습니다. 요청 처리 쓰레드의 스택 트레이스:[{2}]
+webappClassLoader.stackTraceRequestThread=웹 애플리케이션 [{0}]의 쓰레드 [{1}]가 여전히 완료되지 않은 요청을 처리하고 있습니다. 이는 메모리 누수를 유발할 가능성이 높습니다. 표준 컨텍스트 구현의 unloadDelay 속성을 이용하여, 요청 완료 허용 시간을 통제할 수 있습니다. 요청 처리 쓰레드의 스택 트레이스:[{2}]
webappClassLoader.stopThreadFail=웹 애플리케이션 [{1}]을 위한, [{0}](이)라는 이름의 쓰레드를 종료시키지 못했습니다.
webappClassLoader.stopTimerThreadFail=웹 애플리케이션 [{1}]을(를) 위한, [{0}](이)라는 이름의 TimerThread를 종료시키지 못했습니다.
webappClassLoader.stopped=불허되는 접근: 이 웹 애플리케이션 인스턴스는 이미 중지되었습니다. [{0}]을(를) 로드할 수 없습니다. 디버그 목적 및 불허되는 접근을 발생시킨 해당 쓰레드를 종료시키기 위한 시도로서, 다음 스택 트레이스가 생성됩니다.
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_zh_CN.properties tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_zh_CN.properties
--- tomcat10-10.1.40/java/org/apache/catalina/loader/LocalStrings_zh_CN.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/LocalStrings_zh_CN.properties 2026-01-23 19:33:36.000000000 +0000
@@ -50,7 +50,7 @@
webappClassLoader.restrictedPackage=安全冲突,尝试使用受限类[{0}]
webappClassLoader.securityException=尝试在findClassInternal[{1}]中查找类[{0}]时出现安全异常
webappClassLoader.stackTrace=Web应用程序[{0}]似乎启动了一个名为[{1}]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[{2}]
-webappClassLoader.stackTraceRequestThread=web应用程序[{0}]仍在处理一个尚未完成的请求。这很可能会造成内存泄漏。您可以使用标准上下文实现的unloadDelay属性来控制请求完成所允许的时间。请求处理线程的堆栈跟踪:[{2}]
+webappClassLoader.stackTraceRequestThread=web应用程序[{0}]中的线程[{1}]仍在处理一个尚未完成的请求。这很可能会造成内存泄漏。您可以使用标准上下文实现的unloadDelay属性来控制请求完成所允许的时间。请求处理线程的堆栈跟踪:[{2}]
webappClassLoader.stopThreadFail=为web应用程序[{1}]终止线程[{0}]失败
webappClassLoader.stopTimerThreadFail=无法终止名为[{0}]的TimerThread,web应用程序:[{1}]
webappClassLoader.stopped=非法访问:此Web应用程序实例已停止。无法加载[{0}]。为了调试以及终止导致非法访问的线程,将抛出以下堆栈跟踪。
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/ResourceEntry.java tomcat10-10.1.52/java/org/apache/catalina/loader/ResourceEntry.java
--- tomcat10-10.1.40/java/org/apache/catalina/loader/ResourceEntry.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/ResourceEntry.java 2026-01-23 19:33:36.000000000 +0000
@@ -18,8 +18,6 @@
/**
* Resource entry.
- *
- * @author Remy Maucherat
*/
public class ResourceEntry {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/WebappClassLoaderBase.java tomcat10-10.1.52/java/org/apache/catalina/loader/WebappClassLoaderBase.java
--- tomcat10-10.1.40/java/org/apache/catalina/loader/WebappClassLoaderBase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/WebappClassLoaderBase.java 2026-01-23 19:33:36.000000000 +0000
@@ -114,9 +114,6 @@
* IMPLEMENTATION NOTE - As of 8.0, this class loader implements {@link InstrumentableClassLoader},
* permitting web application classes to instrument other classes in the same web application. It does not permit
* instrumentation of system or container classes or classes in other web apps.
- *
- * @author Remy Maucherat
- * @author Craig R. McClanahan
*/
public abstract class WebappClassLoaderBase extends URLClassLoader
implements Lifecycle, InstrumentableClassLoader, WebappProperties, PermissionCheck {
@@ -1104,13 +1101,13 @@
while ((numRead = stream.read(buf)) >= 0) {
baos.write(buf, 0, numRead);
}
- } catch (IOException e) {
- log.error(sm.getString("webappClassLoader.transformError", name), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("webappClassLoader.transformError", name), ioe);
return null;
} finally {
try {
stream.close();
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
}
@@ -1138,7 +1135,7 @@
stream = url.openStream();
}
}
- } catch (IOException e) {
+ } catch (IOException ioe) {
// Ignore
}
if (stream != null) {
@@ -1396,9 +1393,8 @@
// It is not permitted to load resources once the web application has
// been stopped.
if (!state.isAvailable()) {
- String msg = sm.getString("webappClassLoader.stopped", resource);
- IllegalStateException ise = new IllegalStateException(msg);
- log.info(msg, ise);
+ IllegalStateException ise = new IllegalStateException(sm.getString("webappClassLoader.stopped", resource));
+ log.info(ise.getMessage(), ise);
throw ise;
}
}
@@ -2344,7 +2340,11 @@
if (pkg != null) {
boolean sealCheck = true;
if (pkg.isSealed()) {
- sealCheck = pkg.isSealed(codeBase);
+ if (codeBase != null) {
+ sealCheck = pkg.isSealed(codeBase);
+ } else {
+ sealCheck = false;
+ }
} else {
sealCheck = manifest == null || !isPackageSealed(packageName, manifest);
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/loader/WebappLoader.java tomcat10-10.1.52/java/org/apache/catalina/loader/WebappLoader.java
--- tomcat10-10.1.40/java/org/apache/catalina/loader/WebappLoader.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/loader/WebappLoader.java 2026-01-23 19:33:36.000000000 +0000
@@ -22,9 +22,9 @@
import java.io.FilePermission;
import java.io.IOException;
import java.lang.reflect.Constructor;
+import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
-import java.nio.charset.StandardCharsets;
import javax.management.ObjectName;
@@ -43,7 +43,6 @@
import org.apache.tomcat.jakartaee.EESpecProfile;
import org.apache.tomcat.jakartaee.EESpecProfiles;
import org.apache.tomcat.util.ExceptionUtils;
-import org.apache.tomcat.util.buf.UDecoder;
import org.apache.tomcat.util.compat.JreCompat;
import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.res.StringManager;
@@ -56,9 +55,6 @@
* This class loader is configured via the Resources children of its Context prior to calling start(). When
* a new class is required, these Resources will be consulted first to locate the class. If it is not present, the
* system class loader will be used instead.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class WebappLoader extends LifecycleMBeanBase implements Loader {
@@ -322,13 +318,13 @@
MigrationUtil.addJakartaEETransformer(classLoader, getJakartaConverter());
}
- // Configure our repositories
- setClassPath();
-
setPermissions();
classLoader.start();
+ // Configure our repositories
+ setClassPath();
+
String contextName = context.getName();
if (!contextName.startsWith("/")) {
contextName = "/" + contextName;
@@ -507,14 +503,19 @@
URL[] repositories = ((URLClassLoader) loader).getURLs();
for (URL url : repositories) {
String repository = url.toString();
- if (repository.startsWith("file://")) {
- repository = UDecoder.URLDecode(repository.substring(7), StandardCharsets.UTF_8);
- } else if (repository.startsWith("file:")) {
- repository = UDecoder.URLDecode(repository.substring(5), StandardCharsets.UTF_8);
- } else {
+ if (repository == null) {
continue;
}
- if (repository == null) {
+ if (repository.startsWith("file:")) {
+ // Let the JRE handle all the edge cases for URL to path conversion.
+ try {
+ File f = new File(url.toURI());
+ repository = f.getAbsolutePath();
+ } catch (URISyntaxException | IllegalArgumentException e) {
+ // Can't convert from URL to URI. Treat as non-file URL and skip.
+ continue;
+ }
+ } else {
continue;
}
if (classpath.length() > 0) {
@@ -523,8 +524,7 @@
classpath.append(repository);
}
} else if (loader == ClassLoader.getSystemClassLoader()) {
- // From Java 9 the internal class loaders no longer extend
- // URLCLassLoader
+ // From Java 9 the internal class loaders no longer extend URLCLassLoader
String cp = System.getProperty("java.class.path");
if (cp != null && !cp.isEmpty()) {
if (classpath.length() > 0) {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/Constants.java tomcat10-10.1.52/java/org/apache/catalina/manager/Constants.java
--- tomcat10-10.1.40/java/org/apache/catalina/manager/Constants.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/Constants.java 2026-01-23 19:33:36.000000000 +0000
@@ -36,6 +36,7 @@
HTML_HEADER_SECTION =
"\n" +
"\n" +
+ "\n" +
"\n";
BODY_HEADER_SECTION =
@@ -130,7 +131,7 @@
HTML_TAIL_SECTION =
"\n" +
"
\n" +
"\n" +
"\n" +
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java tomcat10-10.1.52/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java
--- tomcat10-10.1.40/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -47,11 +47,6 @@
* However if you use a software that parses the output of HostManagerServlet you won't be able to upgrade
* to this Servlet since the output are not in the same format as from HostManagerServlet
*
- * @author Bip Thelin
- * @author Malcolm Edgar
- * @author Glenn L. Nielsen
- * @author Peter Rossbach
- *
* @see org.apache.catalina.manager.ManagerServlet
*/
public class HTMLHostManagerServlet extends HostManagerServlet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/host/HostManagerServlet.java tomcat10-10.1.52/java/org/apache/catalina/manager/host/HostManagerServlet.java
--- tomcat10-10.1.40/java/org/apache/catalina/manager/host/HostManagerServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/host/HostManagerServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -76,9 +76,6 @@
*
debug - The debugging detail level that controls the amount of information that is logged by this servlet.
* Default is zero.
*
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class HostManagerServlet extends HttpServlet implements ContainerServlet {
@@ -331,7 +328,7 @@
}
try {
appBaseFile = file.getCanonicalFile();
- } catch (IOException e) {
+ } catch (IOException ioe) {
appBaseFile = file;
}
if (!appBaseFile.mkdirs() && !appBaseFile.isDirectory()) {
@@ -355,7 +352,7 @@
}
Path dest = new File(configBaseFile, "manager.xml").toPath();
Files.copy(is, dest);
- } catch (IOException e) {
+ } catch (IOException ioe) {
writer.println(smClient.getString("hostManagerServlet.managerXml"));
return;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/host/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/manager/host/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/manager/host/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/host/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -18,7 +18,7 @@
hostManagerServlet.add=add: ホスト [{0}] を追加
hostManagerServlet.addFailed=FAIL - ホスト [{0}] を追加できません。
-hostManagerServlet.addSuccess=OK - ホスト [{0}] を追加しました
+hostManagerServlet.addSuccess=OK - ホスト [{0}] を追加しました
hostManagerServlet.alreadyHost=FAIL - ホスト名[{0}]のホストが既に存在します
hostManagerServlet.alreadyStarted=FAIL - ホスト [{0}] はすでに開始しています。
hostManagerServlet.alreadyStopped=FAIL - Host [{0}] はすでに停止しています。
@@ -42,7 +42,7 @@
hostManagerServlet.postCommand=FAIL - コマンド [{0}] をGETリクエストで使用しようとしましたが、POSTが必要です
hostManagerServlet.remove=remove: ホスト [{0}] を削除します。
hostManagerServlet.removeFailed=FAIL - Host [{0}] を削除できません。
-hostManagerServlet.removeSuccess=OK - ホスト [{0}] を削除しました
+hostManagerServlet.removeSuccess=OK - ホスト [{0}] を削除しました
hostManagerServlet.start=開始:名前[{0}]のホストを起動しています
hostManagerServlet.startFailed=FAIL - ホスト [{0}] の起動に失敗しました
hostManagerServlet.started=OK - ホスト [{0}] を開始しました
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/host/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/manager/host/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/manager/host/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/host/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -39,13 +39,13 @@
hostManagerServlet.persistFailed=Ошибка - Не удалось сохранить конфигурацию
hostManagerServlet.persisted=OK - Конфигурация сохранена
hostManagerServlet.postCommand=Ошибка - Команда [{0}] была подана при помощи запроса GET, но требуется POST
-hostManagerServlet.remove=remove: Удаление сервера [{0}]
+hostManagerServlet.remove=remove: Удаление хоста [{0}]
hostManagerServlet.removeFailed=Ошибка - Не удалось удалить сервер [{0}]
hostManagerServlet.removeSuccess=OK - Сервер удалён [{0}]
-hostManagerServlet.start=start: Запуск сервера с именем [{0}]
+hostManagerServlet.start=start: Запуск хоста с именем [{0}]
hostManagerServlet.startFailed=Ошибка - Не удалось запустить сервер [{0}]
hostManagerServlet.started=OK - Сервер [{0}] запущен
-hostManagerServlet.stop=stop: Остановка сервера с именем [{0}]
+hostManagerServlet.stop=stop: Остановка хоста с именем [{0}]
hostManagerServlet.stopFailed=Ошибка - Не удалось остановить сервер [{0}]
hostManagerServlet.stopped=OK - Сервер [{0}] остановлен
hostManagerServlet.unknownCommand=Ошибка - Неизвестная команда [{0}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/host/LocalStrings_zh_CN.properties tomcat10-10.1.52/java/org/apache/catalina/manager/host/LocalStrings_zh_CN.properties
--- tomcat10-10.1.40/java/org/apache/catalina/manager/host/LocalStrings_zh_CN.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/host/LocalStrings_zh_CN.properties 2026-01-23 19:33:36.000000000 +0000
@@ -18,7 +18,7 @@
hostManagerServlet.add=添加:添加主机[{0}]
hostManagerServlet.addFailed=失败 - 添加主机 [{0}] 失败
-hostManagerServlet.addSuccess=确定-添加主机[{0}]
+hostManagerServlet.addSuccess=OK - 确定-添加主机[{0}]
hostManagerServlet.alreadyHost=失败 - 主机名称[{0}]已经存在
hostManagerServlet.alreadyStarted=失败 - Host[{0}]已经启动。
hostManagerServlet.alreadyStopped=失败 - 主机[{0}]已经停止
@@ -42,12 +42,12 @@
hostManagerServlet.postCommand=失败 - 尝试通过GET请求使用命令[{0}],但是需要使用POST请求
hostManagerServlet.remove=移除:正在移除主机 [{0}]
hostManagerServlet.removeFailed=失败 - 无法移除主机 [{0}]
-hostManagerServlet.removeSuccess=确定-已删除主机[{0}]
+hostManagerServlet.removeSuccess=OK - 已删除主机[{0}]
hostManagerServlet.start=启动:启动主机[{0}]
hostManagerServlet.startFailed=失败 - 无法启动主机 [{0}]
hostManagerServlet.started=OK - 主机 [{0}] 已启动
hostManagerServlet.stop=停止:停止主机[{0}]
-hostManagerServlet.stopFailed=失败 - 无法停止主机 [{0}]
+hostManagerServlet.stopFailed=OK - 无法停止主机 [{0}]
hostManagerServlet.stopped=OK - 主机 [{0}] 已停止
hostManagerServlet.unknownCommand=失败 - 未知命令 [{0}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/manager/util/SessionUtils.java tomcat10-10.1.52/java/org/apache/catalina/manager/util/SessionUtils.java
--- tomcat10-10.1.40/java/org/apache/catalina/manager/util/SessionUtils.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/manager/util/SessionUtils.java 2026-01-23 19:33:36.000000000 +0000
@@ -32,8 +32,6 @@
/**
* Utility methods on HttpSessions.
- *
- * @author Cédrik LIME
*/
public class SessionUtils {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mapper/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/mapper/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/mapper/LocalStrings_ru.properties 1970-01-01 00:00:00.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mapper/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -0,0 +1,19 @@
+# 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.
+
+# Do not edit this file directly.
+# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
+
+mapper.addHostAlias.success=Зарегистрирован псевдоним [{0}] для хоста [{1}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mapper/Mapper.java tomcat10-10.1.52/java/org/apache/catalina/mapper/Mapper.java
--- tomcat10-10.1.40/java/org/apache/catalina/mapper/Mapper.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mapper/Mapper.java 2026-01-23 19:33:36.000000000 +0000
@@ -41,8 +41,6 @@
/**
* Mapper, which implements the servlet API mapping rules (which are derived from the HTTP rules).
- *
- * @author Remy Maucherat
*/
public final class Mapper {
@@ -439,7 +437,7 @@
* @param resourceOnly true if this wrapper always expects a physical resource to be present (such as a JSP)
*/
private void addWrapper(ContextVersion context, String path, Wrapper wrapper, boolean jspWildCard,
- boolean resourceOnly) {
+ boolean resourceOnly) {
synchronized (context) {
if (path.endsWith("/*")) {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mapper/MapperListener.java tomcat10-10.1.52/java/org/apache/catalina/mapper/MapperListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/mapper/MapperListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mapper/MapperListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -40,9 +40,6 @@
/**
* Mapper listener.
- *
- * @author Remy Maucherat
- * @author Costin Manolache
*/
public class MapperListener extends LifecycleMBeanBase implements ContainerListener, LifecycleListener {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mapper/MappingData.java tomcat10-10.1.52/java/org/apache/catalina/mapper/MappingData.java
--- tomcat10-10.1.40/java/org/apache/catalina/mapper/MappingData.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mapper/MappingData.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,8 +25,6 @@
/**
* Mapping data.
- *
- * @author Remy Maucherat
*/
public class MappingData {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mbeans/ClassNameMBean.java tomcat10-10.1.52/java/org/apache/catalina/mbeans/ClassNameMBean.java
--- tomcat10-10.1.40/java/org/apache/catalina/mbeans/ClassNameMBean.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mbeans/ClassNameMBean.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
*
*
* @param The type that this bean represents.
- *
- * @author Craig R. McClanahan
*/
public class ClassNameMBean extends BaseCatalinaMBean {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mbeans/ConnectorMBean.java tomcat10-10.1.52/java/org/apache/catalina/mbeans/ConnectorMBean.java
--- tomcat10-10.1.40/java/org/apache/catalina/mbeans/ConnectorMBean.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mbeans/ConnectorMBean.java 2026-01-23 19:33:36.000000000 +0000
@@ -27,12 +27,8 @@
import org.apache.tomcat.util.res.StringManager;
/**
- *
* A ModelMBean implementation for the org.apache.coyote.tomcat5.CoyoteConnector
* component.
- *
* A ModelMBean implementation for the org.apache.catalina.Role component.
*
- *
- * @author Craig R. McClanahan
*/
public class RoleMBean extends BaseModelMBean {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mbeans/SparseUserDatabaseMBean.java tomcat10-10.1.52/java/org/apache/catalina/mbeans/SparseUserDatabaseMBean.java
--- tomcat10-10.1.40/java/org/apache/catalina/mbeans/SparseUserDatabaseMBean.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mbeans/SparseUserDatabaseMBean.java 2026-01-23 19:33:36.000000000 +0000
@@ -40,8 +40,6 @@
* register the corresponding user and make it available for management). All the MBeans created for users, groups and
* roles are then discarded when save is invoked.
*
- *
- * @author Craig R. McClanahan
*/
public class SparseUserDatabaseMBean extends BaseModelMBean {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/mbeans/UserMBean.java tomcat10-10.1.52/java/org/apache/catalina/mbeans/UserMBean.java
--- tomcat10-10.1.40/java/org/apache/catalina/mbeans/UserMBean.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/mbeans/UserMBean.java 2026-01-23 19:33:36.000000000 +0000
@@ -35,8 +35,6 @@
*
* A ModelMBean implementation for the org.apache.catalina.User component.
*
- *
- * @author Craig R. McClanahan
*/
public class UserMBean extends BaseModelMBean {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/CombinedRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/CombinedRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/CombinedRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/CombinedRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -359,7 +359,7 @@
// Stack trace will show where this was called from
UnsupportedOperationException uoe =
new UnsupportedOperationException(sm.getString("combinedRealm.getPassword"));
- log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
+ log.error(uoe.getMessage(), uoe);
throw uoe;
}
@@ -369,7 +369,7 @@
// Stack trace will show where this was called from
UnsupportedOperationException uoe =
new UnsupportedOperationException(sm.getString("combinedRealm.getPrincipal"));
- log.error(sm.getString("combinedRealm.unexpectedMethod"), uoe);
+ log.error(uoe.getMessage(), uoe);
throw uoe;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/DataSourceRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/DataSourceRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/DataSourceRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/DataSourceRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -34,11 +34,6 @@
/**
* Implementation of Realm that works with any JDBC JNDI DataSource. See the Realm How-To for more details on how
* to set up the database and for configuration options.
- *
- * @author Glenn L. Nielsen
- * @author Craig R. McClanahan
- * @author Carson McDonald
- * @author Ignacio Ortega
*/
public class DataSourceRealm extends RealmBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/GenericPrincipal.java tomcat10-10.1.52/java/org/apache/catalina/realm/GenericPrincipal.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/GenericPrincipal.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/GenericPrincipal.java 2026-01-23 19:33:36.000000000 +0000
@@ -33,8 +33,6 @@
/**
* Generic implementation of java.security.Principal that is available for use by Realm
* implementations.
- *
- * @author Craig R. McClanahan
*/
public class GenericPrincipal implements TomcatPrincipal, Serializable {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/JAASCallbackHandler.java tomcat10-10.1.52/java/org/apache/catalina/realm/JAASCallbackHandler.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/JAASCallbackHandler.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/JAASCallbackHandler.java 2026-01-23 19:33:36.000000000 +0000
@@ -29,22 +29,15 @@
import org.apache.tomcat.util.res.StringManager;
/**
- *
* Implementation of the JAAS CallbackHandler interface, used to negotiate delivery of the username and
* credentials that were specified to our constructor. No interaction with the user is required (or possible).
- *
*
* This CallbackHandler will pre-digest the supplied password, if required by the
* <Realm> element in server.xml.
- *
*
* At present, JAASCallbackHandler knows how to handle callbacks of type
* javax.security.auth.callback.NameCallback and
* javax.security.auth.callback.PasswordCallback.
- *
- *
- * @author Craig R. McClanahan
- * @author Andrew R. Jaquith
*/
public class JAASCallbackHandler implements CallbackHandler {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/JAASMemoryLoginModule.java tomcat10-10.1.52/java/org/apache/catalina/realm/JAASMemoryLoginModule.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/JAASMemoryLoginModule.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/JAASMemoryLoginModule.java 2026-01-23 19:33:36.000000000 +0000
@@ -66,8 +66,6 @@
* requirements of the GenericPrincipal constructor. It does not actually perform the functionality
* required of a Realm implementation.
*
- *
- * @author Craig R. McClanahan
*/
public class JAASMemoryLoginModule extends MemoryRealm implements LoginModule {
// We need to extend MemoryRealm to avoid class cast
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/JAASRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/JAASRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/JAASRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/JAASRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -115,9 +115,6 @@
* JAASCallbackHandler will digest the password prior to passing it back to the
* LoginModule
*
- *
- * @author Craig R. McClanahan
- * @author Yoav Shapira
*/
public class JAASRealm extends RealmBase {
@@ -360,9 +357,9 @@
try {
Configuration config = getConfig();
loginContext = new LoginContext(appName, null, callbackHandler, config);
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- log.error(sm.getString("jaasRealm.unexpectedError"), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.error(sm.getString("jaasRealm.unexpectedError"), t);
// There is configuration issue with JAAS so mark the realm as
// unavailable
invocationSuccess = false;
@@ -395,7 +392,7 @@
}
} catch (AccountExpiredException e) {
if (log.isDebugEnabled()) {
- log.debug(sm.getString("jaasRealm.accountExpired", username));
+ log.debug(sm.getString("jaasRealm.accountExpired", username), e);
}
// JAAS checked LoginExceptions are successful authentication
// invocations so mark JAAS realm as available
@@ -403,7 +400,7 @@
return null;
} catch (CredentialExpiredException e) {
if (log.isDebugEnabled()) {
- log.debug(sm.getString("jaasRealm.credentialExpired", username));
+ log.debug(sm.getString("jaasRealm.credentialExpired", username), e);
}
// JAAS checked LoginExceptions are successful authentication
// invocations so mark JAAS realm as available
@@ -411,7 +408,7 @@
return null;
} catch (FailedLoginException e) {
if (log.isDebugEnabled()) {
- log.debug(sm.getString("jaasRealm.failedLogin", username));
+ log.debug(sm.getString("jaasRealm.failedLogin", username), e);
}
// JAAS checked LoginExceptions are successful authentication
// invocations so mark JAAS realm as available
@@ -423,9 +420,9 @@
// invocations so mark JAAS realm as available
invocationSuccess = true;
return null;
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- log.error(sm.getString("jaasRealm.unexpectedError"), e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.error(sm.getString("jaasRealm.unexpectedError"), t);
// JAAS throws exception different from LoginException so mark the
// realm as unavailable
invocationSuccess = false;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/JNDIRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/JNDIRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/JNDIRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/JNDIRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -133,9 +133,6 @@
* descriptor allows applications to refer to roles programmatically by names other than those used in the directory
* server itself.
*
- *
- * @author John Holman
- * @author Craig R. McClanahan
*/
public class JNDIRealm extends RealmBase {
@@ -1156,9 +1153,9 @@
} catch (NullPointerException | NamingException e) {
/*
* BZ 61313 NamingException may or may not indicate an error that is recoverable via fail over.
- * Therefore, a decision needs to be made whether to fail over or not. Generally, attempting to fail over
- * when it is not appropriate is better than not failing over when it is appropriate so the code always
- * attempts to fail over for NamingExceptions.
+ * Therefore, a decision needs to be made whether to fail over or not. Generally, attempting to fail
+ * over when it is not appropriate is better than not failing over when it is appropriate so the code
+ * always attempts to fail over for NamingExceptions.
*/
/*
@@ -1832,7 +1829,7 @@
}
boolean validated = false;
- Hashtable, ?> preservedEnvironment = context.getEnvironment();
+ Hashtable,?> preservedEnvironment = context.getEnvironment();
// Elicit an LDAP bind operation using the provided user credentials
try {
@@ -1848,7 +1845,7 @@
validated = true;
} catch (AuthenticationException e) {
if (containerLog.isTraceEnabled()) {
- containerLog.trace(" bind attempt failed");
+ containerLog.trace(" bind attempt failed", e);
}
} finally {
// Restore GSSAPI SASL if previously configured
@@ -2217,8 +2214,8 @@
if (tls != null) {
try {
tls.close();
- } catch (IOException e) {
- containerLog.error(sm.getString("jndiRealm.tlsClose"), e);
+ } catch (IOException ioe) {
+ containerLog.error(sm.getString("jndiRealm.tlsClose"), ioe);
}
}
// Close our opened connection
@@ -2570,7 +2567,7 @@
try {
Object o = constructInstance(className);
if (o instanceof SSLSocketFactory) {
- return sslSocketFactory;
+ return (SSLSocketFactory) o;
} else {
throw new IllegalArgumentException(sm.getString("jndiRealm.invalidSslSocketFactory", className));
}
@@ -2629,8 +2626,10 @@
try {
SSLSession negotiate = tls.negotiate(getSSLSocketFactory());
containerLog.debug(sm.getString("jndiRealm.negotiatedTls", negotiate.getProtocol()));
- } catch (IOException e) {
- throw new NamingException(e.getMessage());
+ } catch (IOException ioe) {
+ NamingException ne = new NamingException(ioe.getMessage());
+ ne.initCause(ioe);
+ throw ne;
}
} finally {
if (result != null) {
@@ -2763,8 +2762,8 @@
/**
* Given a string containing LDAP patterns for user locations (separated by parentheses in a pseudo-LDAP search
- * string format - "(location1)(location2)"), returns an array of those paths. Real LDAP search strings are supported
- * as well (though only the "|" "OR" type).
+ * string format - "(location1)(location2)"), returns an array of those paths. Real LDAP search strings are
+ * supported as well (though only the "|" "OR" type).
*
* @param userPatternString - a string LDAP search paths surrounded by parentheses
*
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/realm/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/realm/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -17,6 +17,7 @@
# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
dataSourceRealm.getPassword.exception=Исключение при получении пароля для [{0}]
+dataSourceRealm.getRoles.exception=Ошибка получения ролей для [{0}]
lockOutRealm.authLockedUser=Заблокированный пользователь [{0}] совершил попытку авторизоваться
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/LockOutRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/LockOutRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/LockOutRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/LockOutRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -218,7 +218,7 @@
// Check to see if user is locked
// Otherwise, user has not, yet, exceeded lock thresholds
return lockRecord.getFailures() >= failureCount &&
- (System.currentTimeMillis() - lockRecord.getLastFailureTime()) / 1000 < lockOutTime;
+ (System.currentTimeMillis() - lockRecord.getLastFailureTime()) / 1000 < lockOutTime;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/MemoryRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/MemoryRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/MemoryRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/MemoryRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -38,8 +38,6 @@
* IMPLEMENTATION NOTE: It is assumed that the in-memory collection representing our defined users (and
* their roles) is initialized at application startup and never modified again. Therefore, no thread synchronization is
* performed around accesses to the principals collection.
- *
- * @author Craig R. McClanahan
*/
public class MemoryRealm extends RealmBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/MemoryRuleSet.java tomcat10-10.1.52/java/org/apache/catalina/realm/MemoryRuleSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/MemoryRuleSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/MemoryRuleSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,8 +25,6 @@
*
* RuleSet for recognizing the users defined in the XML file processed by MemoryRealm.
*
- *
- * @author Craig R. McClanahan
*/
public class MemoryRuleSet implements RuleSet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java tomcat10-10.1.52/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java 2026-01-23 19:33:36.000000000 +0000
@@ -58,6 +58,7 @@
private Charset encoding = StandardCharsets.UTF_8;
private String algorithm = null;
+ private boolean digestInRfc3112Order = false;
public String getEncoding() {
@@ -91,6 +92,16 @@
}
+ public boolean getDigestInRfc3112Order() {
+ return digestInRfc3112Order;
+ }
+
+
+ public void setDigestInRfc3112Order(boolean digestInRfc3112Order) {
+ this.digestInRfc3112Order = digestInRfc3112Order;
+ }
+
+
@Override
public boolean matches(String inputCredentials, String storedCredentials) {
if (inputCredentials == null || storedCredentials == null) {
@@ -162,7 +173,12 @@
if (salt == null) {
userDigest = ConcurrentMessageDigest.digest(algorithm, iterations, inputCredentialbytes);
} else {
- userDigest = ConcurrentMessageDigest.digest(algorithm, iterations, salt, inputCredentialbytes);
+ if (digestInRfc3112Order) {
+ // RFC 3112 states that the input order for the digest is credentials then salt
+ userDigest = ConcurrentMessageDigest.digest(algorithm, iterations, inputCredentialbytes, salt);
+ } else {
+ userDigest = ConcurrentMessageDigest.digest(algorithm, iterations, salt, inputCredentialbytes);
+ }
}
return HexUtils.toHexString(userDigest);
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/NullRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/NullRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/NullRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/NullRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,8 @@
import java.security.Principal;
/**
- * Minimal Realm implementation that always returns null when an attempt is made to validate a username and password.
- * It is intended to be used as a default Realm implementation when no other Realm is specified.
+ * Minimal Realm implementation that always returns null when an attempt is made to validate a username and password. It
+ * is intended to be used as a default Realm implementation when no other Realm is specified.
*/
public class NullRealm extends RealmBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/RealmBase.java tomcat10-10.1.52/java/org/apache/catalina/realm/RealmBase.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/RealmBase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/RealmBase.java 2026-01-23 19:33:36.000000000 +0000
@@ -69,8 +69,6 @@
/**
* Simple implementation of Realm that reads an XML file to configure the valid users, passwords, and roles. The
* file format (and default file location) are identical to those currently supported by Tomcat 3.X.
- *
- * @author Craig R. McClanahan
*/
public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/realm/UserDatabaseRealm.java tomcat10-10.1.52/java/org/apache/catalina/realm/UserDatabaseRealm.java
--- tomcat10-10.1.40/java/org/apache/catalina/realm/UserDatabaseRealm.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/realm/UserDatabaseRealm.java 2026-01-23 19:33:36.000000000 +0000
@@ -39,8 +39,6 @@
* available through the JNDI resources configured for this instance of Catalina. Set the resourceName
* parameter to the JNDI resources name for the configured instance of UserDatabase that we should consult.
*
- * @author Craig R. McClanahan
- *
* @since 4.1
*/
public class UserDatabaseRealm extends RealmBase {
@@ -112,8 +110,7 @@
* Determines whether this Realm is configured to obtain the associated {@link UserDatabase} from the global JNDI
* context or a local (web application) JNDI context.
*
- * @return {@code true} if a local JNDI context will be used, {@code false} if the global JNDI context will be
- * used
+ * @return {@code true} if a local JNDI context will be used, {@code false} if the global JNDI context will be used
*/
public boolean getLocalJndiResource() {
return localJndiResource;
@@ -220,13 +217,13 @@
containerLog.error(sm.getString("userDatabaseRealm.noNamingContext"));
return null;
}
- context = getServer().getGlobalNamingContext();
+ context = server.getGlobalNamingContext();
}
database = (UserDatabase) context.lookup(resourceName);
- } catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
if (containerLog != null) {
- containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), e);
+ containerLog.error(sm.getString("userDatabaseRealm.lookup", resourceName), t);
}
database = null;
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/security/SecurityClassLoad.java tomcat10-10.1.52/java/org/apache/catalina/security/SecurityClassLoad.java
--- tomcat10-10.1.40/java/org/apache/catalina/security/SecurityClassLoad.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/security/SecurityClassLoad.java 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,6 @@
/**
* Static class used to preload java classes when using the Java SecurityManager so that the defineClassInPackage
* RuntimePermission does not trigger an AccessControlException.
- *
- * @author Glenn L. Nielsen
*/
public final class SecurityClassLoad {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/security/SecurityConfig.java tomcat10-10.1.52/java/org/apache/catalina/security/SecurityConfig.java
--- tomcat10-10.1.40/java/org/apache/catalina/security/SecurityConfig.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/security/SecurityConfig.java 2026-01-23 19:33:36.000000000 +0000
@@ -24,8 +24,6 @@
/**
* Util class to protect Catalina against package access and insertion. The code are been moved from Catalina.java
- *
- * @author the Catalina.java authors
*/
public final class SecurityConfig {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/security/SecurityListener.java tomcat10-10.1.52/java/org/apache/catalina/security/SecurityListener.java
--- tomcat10-10.1.40/java/org/apache/catalina/security/SecurityListener.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/security/SecurityListener.java 2026-01-23 19:33:36.000000000 +0000
@@ -221,8 +221,7 @@
if (allowedAgeDays >= 0) {
String buildDateString = ServerInfo.getServerBuiltISO();
- if (null == buildDateString || buildDateString.isEmpty() ||
- !Character.isDigit(buildDateString.charAt(0))) {
+ if (null == buildDateString || buildDateString.isEmpty() || !Character.isDigit(buildDateString.charAt(0))) {
log.warn(sm.getString("SecurityListener.buildDateUnreadable", buildDateString));
} else {
try {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/CGIServlet.java tomcat10-10.1.52/java/org/apache/catalina/servlets/CGIServlet.java
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/CGIServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/CGIServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -43,16 +43,21 @@
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
+import jakarta.servlet.UnavailableException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
+import org.apache.catalina.Globals;
+import org.apache.catalina.WebResource;
+import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.util.IOTools;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.compat.JrePlatform;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.res.StringManager;
@@ -192,17 +197,12 @@
*
Confirm use of ServletInputStream.available() in CGIRunner.run() is not needed
*
[add more to this TODO list]
*
- *
- * @author Martin T Dengler [root@martindengler.com]
- * @author Amy Roh
*/
public final class CGIServlet extends HttpServlet {
private static final Log log = LogFactory.getLog(CGIServlet.class);
private static final StringManager sm = StringManager.getManager(CGIServlet.class);
- /* some vars below copied from Craig R. McClanahan's InvokerServlet */
-
private static final long serialVersionUID = 1L;
private static final Set DEFAULT_SUPER_METHODS = new HashSet<>();
@@ -210,9 +210,9 @@
private static final String ALLOW_ANY_PATTERN = ".*";
static {
- DEFAULT_SUPER_METHODS.add("HEAD");
- DEFAULT_SUPER_METHODS.add("OPTIONS");
- DEFAULT_SUPER_METHODS.add("TRACE");
+ DEFAULT_SUPER_METHODS.add(Method.HEAD);
+ DEFAULT_SUPER_METHODS.add(Method.OPTIONS);
+ DEFAULT_SUPER_METHODS.add(Method.TRACE);
if (JrePlatform.IS_WINDOWS) {
DEFAULT_CMD_LINE_ARGUMENTS_DECODED_PATTERN = Pattern.compile("[\\w\\Q-.\\/:\\E]+");
@@ -243,6 +243,8 @@
private final Set cgiMethods = new HashSet<>();
private boolean cgiMethodsAll = false;
+ private transient WebResourceRoot resources = null;
+
/**
* The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process.
@@ -283,9 +285,6 @@
/**
* Sets instance variables.
- *
- * Modified from Craig R. McClanahan's InvokerServlet
- *
*
* @param config a ServletConfig object containing the servlet's configuration and initialization
* parameters
@@ -362,8 +361,8 @@
}
}
} else {
- cgiMethods.add("GET");
- cgiMethods.add("POST");
+ cgiMethods.add(Method.GET);
+ cgiMethods.add(Method.POST);
}
if (getServletConfig().getInitParameter("cmdLineArgumentsEncoded") != null) {
@@ -378,14 +377,18 @@
} else if (value != null) {
cmdLineArgumentsDecodedPattern = Pattern.compile(value);
}
+
+ // Load the web resources
+ resources = (WebResourceRoot) getServletContext().getAttribute(Globals.RESOURCES_ATTR);
+
+ if (resources == null) {
+ throw new UnavailableException(sm.getString("cgiServlet.noResources"));
+ }
}
/**
* Logs important Servlet API and container information.
- *
- * Based on SnoopAllServlet by Craig R. McClanahan
- *
*
* @param req HttpServletRequest object used as source of information
*/
@@ -541,7 +544,7 @@
CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(), cgiEnv.getEnvironment(), cgiEnv.getWorkingDirectory(),
cgiEnv.getParameters());
- if ("POST".equals(req.getMethod())) {
+ if (Method.POST.equals(req.getMethod())) {
cgi.setInput(req.getInputStream());
}
cgi.setResponse(res);
@@ -564,7 +567,7 @@
@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
// Note: This method will never be called if cgiMethods is "*" so that
- // case does nto need to be handled here.
+ // case does not need to be handled here.
Set allowedMethods = new HashSet<>();
allowedMethods.addAll(cgiMethods);
allowedMethods.addAll(DEFAULT_SUPER_METHODS);
@@ -621,9 +624,6 @@
/** pathInfo for the current request */
private String pathInfo = null;
- /** real file system directory of the enclosing servlet's web app */
- private String webAppRootDir = null;
-
/** tempdir for context - used to expand scripts in unexpanded wars */
private File tmpDir = null;
@@ -677,7 +677,6 @@
*/
protected void setupFromContext(ServletContext context) {
this.context = context;
- this.webAppRootDir = context.getRealPath("/");
this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR);
}
@@ -715,8 +714,8 @@
// does not contain an unencoded "=" this is an indexed query.
// The parsed query string becomes the command line parameters
// for the cgi command.
- if (enableCmdLineArguments && (req.getMethod().equals("GET") || req.getMethod().equals("POST") ||
- req.getMethod().equals("HEAD"))) {
+ if (enableCmdLineArguments && (Method.GET.equals(req.getMethod()) || Method.POST.equals(req.getMethod()) ||
+ Method.HEAD.equals(req.getMethod()))) {
String qs;
if (isIncluded) {
qs = (String) req.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING);
@@ -781,10 +780,9 @@
* cgiPathPrefix is defined by setting this servlet's cgiPathPrefix init parameter
*
*
- * @param pathInfo String from HttpServletRequest.getPathInfo()
- * @param webAppRootDir String from context.getRealPath("/")
* @param contextPath String as from HttpServletRequest.getContextPath()
* @param servletPath String as from HttpServletRequest.getServletPath()
+ * @param pathInfo String from HttpServletRequest.getPathInfo()
* @param cgiPathPrefix subdirectory of webAppRootDir below which the web app's CGIs may be stored; can be null.
* The CGI search path will start at webAppRootDir + File.separator + cgiPathPrefix (or
* webAppRootDir alone if cgiPathPrefix is null). cgiPathPrefix is defined by setting
@@ -801,59 +799,104 @@
* found
*
*/
- protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath,
- String cgiPathPrefix) {
- String path;
- String name;
- String scriptname;
-
- if (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) {
- // strip the trailing "/" from the webAppRootDir
- webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1));
- }
+ protected String[] findCGI(String contextPath, String servletPath, String pathInfo, String cgiPathPrefix) {
- if (cgiPathPrefix != null) {
- webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix;
- }
+ StringBuilder cgiPath = new StringBuilder();
+ StringBuilder urlPath = new StringBuilder();
- if (log.isTraceEnabled()) {
- log.trace(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir));
- }
+ WebResource cgiScript = null;
- File currentLocation = new File(webAppRootDir);
- StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/");
- if (log.isTraceEnabled()) {
- log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath()));
+ if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) {
+ cgiPath.append(servletPath);
+ } else {
+ cgiPath.append('/');
+ cgiPath.append(cgiPathPrefix);
}
- StringBuilder cginameBuilder = new StringBuilder();
- while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
- String nextElement = (String) dirWalker.nextElement();
- currentLocation = new File(currentLocation, nextElement);
- cginameBuilder.append('/').append(nextElement);
+ urlPath.append(servletPath);
+
+ StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/");
+
+ while (pathWalker.hasMoreElements() && (cgiScript == null || !cgiScript.isFile())) {
+ String urlSegment = pathWalker.nextToken();
+ cgiPath.append('/');
+ cgiPath.append(urlSegment);
+ urlPath.append('/');
+ urlPath.append(urlSegment);
if (log.isTraceEnabled()) {
- log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath()));
+ log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString()));
}
+ cgiScript = resources.getResource(cgiPath.toString());
}
- String cginame = cginameBuilder.toString();
- if (!currentLocation.isFile()) {
+
+ // No script was found
+ if (cgiScript == null || !cgiScript.isFile()) {
return new String[] { null, null, null, null };
}
- path = currentLocation.getAbsolutePath();
- name = currentLocation.getName();
+ // Set-up return values
+ String path = null;
+ String scriptName = null;
+ String cgiName = null;
+ String name = null;
- if (servletPath.startsWith(cginame)) {
- scriptname = contextPath + cginame;
- } else {
- scriptname = contextPath + servletPath + cginame;
+ path = cgiScript.getCanonicalPath();
+ if (path == null) {
+ /*
+ * The script doesn't exist directly on the file system. It might be located in an archive or similar.
+ * Such scripts are extracted to the web application's temporary file location.
+ */
+ File tmpCgiFile = new File(tmpDir + cgiPath.toString());
+ if (!tmpCgiFile.exists()) {
+
+ // Create directories
+ File parent = tmpCgiFile.getParentFile();
+ if (!parent.mkdirs() && !parent.isDirectory()) {
+ log.warn(sm.getString("cgiServlet.expandCreateDirFail", parent.getAbsolutePath()));
+ return new String[] { null, null, null, null };
+ }
+
+ try (InputStream is = cgiScript.getInputStream()) {
+ synchronized (expandFileLock) {
+ // Check if file was created by concurrent request
+ if (!tmpCgiFile.exists()) {
+ try {
+ Files.copy(is, tmpCgiFile.toPath());
+ } catch (IOException ioe) {
+ log.warn(sm.getString("cgiServlet.expandFail", cgiScript.getURL(),
+ tmpCgiFile.getAbsolutePath()), ioe);
+ if (tmpCgiFile.exists()) {
+ if (!tmpCgiFile.delete()) {
+ log.warn(sm.getString("cgiServlet.expandDeleteFail",
+ tmpCgiFile.getAbsolutePath()));
+ }
+ }
+ return new String[] { null, null, null, null };
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("cgiServlet.expandOk", cgiScript.getURL(),
+ tmpCgiFile.getAbsolutePath()));
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScript.getURL()), ioe);
+ }
+ }
+ path = tmpCgiFile.getAbsolutePath();
}
+ scriptName = urlPath.toString();
+ cgiName = scriptName.substring(servletPath.length());
+ name = scriptName.substring(scriptName.lastIndexOf('/') + 1);
+
if (log.isTraceEnabled()) {
- log.trace(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame));
+ log.trace(sm.getString("cgiServlet.find.found", name, path, scriptName, cgiName));
}
- return new String[] { path, scriptname, cginame, name };
+
+ return new String[] { path, scriptName, cgiName, name };
}
+
/**
* Constructs the CGI environment to be supplied to the invoked CGI script; relies heavily on Servlet API
* methods and findCGI
@@ -888,13 +931,7 @@
sPathInfoOrig = this.pathInfo;
sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;
- if (webAppRootDir == null) {
- // The app has not been deployed in exploded form
- webAppRootDir = tmpDir.toString();
- expandCGIScript();
- }
-
- sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix);
+ sCGINames = findCGI(contextPath, servletPath, sPathInfoOrig, cgiPathPrefix);
sCGIFullPath = sCGINames[0];
sCGIScriptName = sCGINames[1];
@@ -1021,93 +1058,6 @@
}
/**
- * Extracts requested resource from web app archive to context work directory to enable CGI script to be
- * executed.
- */
- protected void expandCGIScript() {
- StringBuilder srcPath = new StringBuilder();
- StringBuilder destPath = new StringBuilder();
- InputStream is = null;
-
- // paths depend on mapping
- if (cgiPathPrefix == null) {
- srcPath.append(pathInfo);
- is = context.getResourceAsStream(srcPath.toString());
- destPath.append(tmpDir);
- destPath.append(pathInfo);
- } else {
- // essentially same search algorithm as findCGI()
- srcPath.append(cgiPathPrefix);
- StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/");
- // start with first element
- while (pathWalker.hasMoreElements() && (is == null)) {
- srcPath.append('/');
- srcPath.append(pathWalker.nextElement());
- is = context.getResourceAsStream(srcPath.toString());
- }
- destPath.append(tmpDir);
- destPath.append('/');
- destPath.append(srcPath);
- }
-
- if (is == null) {
- // didn't find anything, give up now
- log.warn(sm.getString("cgiServlet.expandNotFound", srcPath));
- return;
- }
-
- try {
- File f = new File(destPath.toString());
- if (f.exists()) {
- // Don't need to expand if it already exists
- return;
- }
-
- // create directories
- File dir = f.getParentFile();
- if (!dir.mkdirs() && !dir.isDirectory()) {
- log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath()));
- return;
- }
-
- try {
- synchronized (expandFileLock) {
- // make sure file doesn't exist
- if (f.exists()) {
- return;
- }
-
- // create file
- if (!f.createNewFile()) {
- return;
- }
-
- Files.copy(is, f.toPath());
-
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath));
- }
- }
- } catch (IOException ioe) {
- log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe);
- // delete in case file is corrupted
- if (f.exists()) {
- if (!f.delete()) {
- log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath()));
- }
- }
- }
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e);
- }
- }
- }
-
-
- /**
* Returns important CGI environment information in a multi-line text format.
*
* @return CGI environment info
@@ -1402,9 +1352,9 @@
*
Allowed characters in path segments: This implementation does not allow non-terminal NULL segments
* in the path -- IOExceptions may be thrown;
*
"." and ".." path segments: This implementation does not allow
- * "." and ".." in the path, and such characters will result in an IOException
- * being thrown (this should never happen since Tomcat normalises the requestURI before determining the
- * contextPath, servletPath and pathInfo);
+ * "." and ".." in the path, and such characters will result in an IOException being
+ * thrown (this should never happen since Tomcat normalises the requestURI before determining the contextPath,
+ * servletPath and pathInfo);
*
Implementation limitations: This implementation does not impose any limitations except as
* documented above. This implementation may be limited by the servlet container used to house this
* implementation. In particular, all the primary CGI variable values are derived either directly or indirectly
@@ -1435,14 +1385,10 @@
throw new IOException(sm.getString("cgiServlet.invalidCommand", command));
}
- /*
- * original content/structure of this section taken from
- * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4216884 with major modifications by Martin Dengler
- */
Runtime rt;
BufferedReader cgiHeaderReader = null;
InputStream cgiOutput = null;
- BufferedReader commandsStdErr ;
+ BufferedReader commandsStdErr;
Thread errReaderThread = null;
BufferedOutputStream commandsStdIn;
Process proc = null;
@@ -1552,9 +1498,9 @@
}
} // replacement for Process.waitFor()
- } catch (IOException e) {
- log.warn(sm.getString("cgiServlet.runFail"), e);
- throw e;
+ } catch (IOException ioe) {
+ log.warn(sm.getString("cgiServlet.runFail"), ioe);
+ throw ioe;
} finally {
// Close the header reader
if (cgiHeaderReader != null) {
@@ -1577,7 +1523,7 @@
try {
errReaderThread.join(stderrTimeout);
} catch (InterruptedException e) {
- log.warn(sm.getString("cgiServlet.runReaderInterrupt"));
+ log.warn(sm.getString("cgiServlet.runReaderInterrupt"), e);
}
}
if (proc != null) {
@@ -1655,13 +1601,13 @@
log.warn(sm.getString("cgiServlet.runStdErr", line));
lineCount++;
}
- } catch (IOException e) {
- log.warn(sm.getString("cgiServlet.runStdErrFail"), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("cgiServlet.runStdErrFail"), ioe);
} finally {
try {
rdr.close();
- } catch (IOException e) {
- log.warn(sm.getString("cgiServlet.runStdErrFail"), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("cgiServlet.runStdErrFail"), ioe);
}
}
if (lineCount > 0) {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/DefaultServlet.java tomcat10-10.1.52/java/org/apache/catalina/servlets/DefaultServlet.java
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/DefaultServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/DefaultServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -79,6 +79,7 @@
import org.apache.catalina.webresources.CachedResource;
import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.http.ResponseUtil;
import org.apache.tomcat.util.http.parser.ContentRange;
import org.apache.tomcat.util.http.parser.EntityTag;
@@ -136,9 +137,6 @@
* Then a request to /context/static/images/tomcat.jpg will succeed while a request to
* /context/images/tomcat2.jpg will fail.
*
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class DefaultServlet extends HttpServlet {
@@ -687,8 +685,8 @@
}
} else {
try {
- resp.sendError(resourceInputStream != null ?
- HttpServletResponse.SC_CONFLICT : HttpServletResponse.SC_BAD_REQUEST);
+ resp.sendError(resourceInputStream != null ? HttpServletResponse.SC_CONFLICT :
+ HttpServletResponse.SC_BAD_REQUEST);
} catch (IllegalStateException e) {
// Already committed, ignore
}
@@ -697,7 +695,7 @@
if (resourceInputStream != null) {
try {
resourceInputStream.close();
- } catch (IOException ioe) {
+ } catch (IOException ignore) {
// Ignore
}
}
@@ -756,17 +754,18 @@
int numBytesRead;
byte[] transferBuffer = new byte[BUFFER_SIZE];
try (BufferedInputStream requestBufInStream = new BufferedInputStream(req.getInputStream(), BUFFER_SIZE)) {
+ long rangeBytes = range.getEnd() - range.getStart() + 1L;
while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
received += numBytesRead;
- if (received > range.getEnd() - range.getStart()) {
+ if (received > rangeBytes) {
throw new IllegalStateException(sm.getString("defaultServlet.wrongByteCountForRange",
- String.valueOf(received), String.valueOf(range.getEnd() - range.getStart())));
+ String.valueOf(received), String.valueOf(rangeBytes)));
}
randAccessContentFile.write(transferBuffer, 0, numBytesRead);
}
- if (received < range.getEnd() - range.getStart()) {
+ if (received < rangeBytes) {
throw new IllegalStateException(sm.getString("defaultServlet.wrongByteCountForRange",
- String.valueOf(received), String.valueOf(range.getEnd() - range.getStart())));
+ String.valueOf(received), String.valueOf(rangeBytes)));
}
}
@@ -1096,7 +1095,7 @@
response.setContentType(contentType);
}
}
- if (resource.isFile() && contentLength >= 0 && (!serveContent || ostream != null)) {
+ if (resource.isFile() && contentLength >= 0 && (!serveContent || ostream != null || writer != null)) {
if (debug > 0) {
log("DefaultServlet.serveFile: contentLength=" + contentLength);
}
@@ -1110,8 +1109,8 @@
if (serveContent) {
try {
response.setBufferSize(output);
- } catch (IllegalStateException e) {
- // Silent catch
+ } catch (IllegalStateException ignore) {
+ // Content has already been written - this must be an include. Ignore the error and continue.
}
InputStream renderResult = null;
if (ostream == null) {
@@ -1224,8 +1223,8 @@
if (serveContent) {
try {
response.setBufferSize(output);
- } catch (IllegalStateException e) {
- // Silent catch
+ } catch (IllegalStateException ignore) {
+ // Content has already been written - this must be an include. Ignore the error and continue.
}
if (ostream != null) {
if (!checkSendfile(request, response, resource, contentLength, range)) {
@@ -1242,7 +1241,7 @@
try {
response.setBufferSize(output);
} catch (IllegalStateException e) {
- // Silent catch
+ // Content has already been written - this must be an include. Ignore the error and continue.
}
if (ostream != null) {
copy(resource, contentLength, ostream, ranges, contentType);
@@ -1572,7 +1571,7 @@
return FULL;
}
- if (!"GET".equals(request.getMethod()) || !isRangeRequestsSupported()) {
+ if (!Method.GET.equals(request.getMethod()) || !isRangeRequestsSupported()) {
// RFC 9110 - Section 14.2: GET is the only method for which range handling is defined.
// Otherwise MUST ignore a Range header field
return FULL;
@@ -2038,15 +2037,15 @@
}
IOException e = copyRange(reader, new PrintWriter(buffer));
if (debug > 10) {
- log("readme '" + readmeFile + "' output error: " + e.getMessage());
+ log("readme '" + readmeFile + "' output error: " + ((e != null) ? e.getMessage() : ""));
}
- } catch (IOException e) {
- log(sm.getString("defaultServlet.readerCloseFailed"), e);
+ } catch (IOException ioe) {
+ log(sm.getString("defaultServlet.readerCloseFailed"), ioe);
} finally {
if (reader != null) {
try {
reader.close();
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
}
@@ -2312,7 +2311,7 @@
WebResource resource) {
String method = request.getMethod();
- if (!"GET".equals(method) && !"HEAD".equals(method)) {
+ if (!Method.GET.equals(method) && !Method.HEAD.equals(method)) {
return true;
}
@@ -2420,7 +2419,7 @@
// 304 Not Modified.
// For every other method, 412 Precondition Failed is sent
// back.
- if ("GET".equals(request.getMethod()) || "HEAD".equals(request.getMethod())) {
+ if (Method.GET.equals(request.getMethod()) || Method.HEAD.equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setHeader("ETag", resourceETag);
} else {
@@ -2510,8 +2509,7 @@
if (headerValue.length() > 2 && (headerValue.charAt(0) == '"' || headerValue.charAt(2) == '"')) {
boolean weakETag = headerValue.startsWith("W/\"");
- if ((!weakETag && headerValue.charAt(0) != '"') ||
- headerValue.charAt(headerValue.length() - 1) != '"' ||
+ if ((!weakETag && headerValue.charAt(0) != '"') || headerValue.charAt(headerValue.length() - 1) != '"' ||
headerValue.indexOf('"', weakETag ? 3 : 1) != headerValue.length() - 1) {
// Not a single entity tag
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
@@ -2524,7 +2522,7 @@
long headerValueTime = -1L;
try {
headerValueTime = request.getDateHeader("If-Range");
- } catch (IllegalArgumentException e) {
+ } catch (IllegalArgumentException ignore) {
// Ignore
}
if (headerValueTime >= 0) {
@@ -2725,8 +2723,8 @@
break;
}
ostream.write(buffer, 0, len);
- } catch (IOException e) {
- exception = e;
+ } catch (IOException ioe) {
+ exception = ioe;
break;
}
}
@@ -2756,8 +2754,8 @@
break;
}
writer.write(buffer, 0, len);
- } catch (IOException e) {
- exception = e;
+ } catch (IOException ioe) {
+ exception = ioe;
break;
}
}
@@ -2786,8 +2784,8 @@
long skipped;
try {
skipped = istream.skip(start);
- } catch (IOException e) {
- return e;
+ } catch (IOException ioe) {
+ return ioe;
}
if (skipped < start) {
return new IOException(sm.getString("defaultServlet.skipfail", Long.valueOf(skipped), Long.valueOf(start)));
@@ -2808,8 +2806,8 @@
ostream.write(buffer, 0, (int) bytesToRead);
bytesToRead = 0;
}
- } catch (IOException e) {
- exception = e;
+ } catch (IOException ioe) {
+ exception = ioe;
len = -1;
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings.properties tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -21,7 +21,6 @@
cgiServlet.expandCreateDirFail=Failed to create destination directory [{0}] for script expansion
cgiServlet.expandDeleteFail=Failed to delete file at [{0}] after IOException during expansion
cgiServlet.expandFail=Failed to expand script at path [{0}] to [{1}]
-cgiServlet.expandNotFound=Unable to expand [{0}] as it could not be found
cgiServlet.expandOk=Expanded script at path [{0}] to [{1}]
cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}]
cgiServlet.find.location=Looking for a file at [{0}]
@@ -29,6 +28,7 @@
cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did not match the configured cmdLineArgumentsDecoded pattern [{1}]
cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}]
cgiServlet.invalidCommand=Illegal Character in CGI command path ('.' or '..') detected, not running CGI [{0}]
+cgiServlet.noResources=No static resources were found
cgiServlet.notReady=CGI Servlet is not ready to run
cgiServlet.runBadHeader=Bad header line [{0}]
cgiServlet.runFail=I/O problems processing CGI
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_fr.properties tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_fr.properties
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_fr.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_fr.properties 2026-01-23 19:33:36.000000000 +0000
@@ -21,7 +21,6 @@
cgiServlet.expandCreateDirFail=Echec de la création du répertoire de destination [{0}] pour la décompression du script
cgiServlet.expandDeleteFail=Impossible d''effacer le fichier [{0}] suite à une IOException pendant la décompression
cgiServlet.expandFail=Impossible de faire l''expansion du script au chemin [{0}] vers [{1}]
-cgiServlet.expandNotFound=Impossible de décompresser [{0}] car il n''a pas été trouvé
cgiServlet.expandOk=Extrait le script du chemin [{0}] vers [{1}]
cgiServlet.find.found=Trouvé le CGI : nom [{0}], chemin [{1}], nom de script [{2}] et nom du CGI [{3}]
cgiServlet.find.location=Recherche d''un fichier en [{0}]
@@ -29,6 +28,7 @@
cgiServlet.invalidArgumentDecoded=Les paramètres de ligne de commande décodés [{0}] ne correspondent pas au modèle cmdLineArgumentsDecoded configuré [{1}]
cgiServlet.invalidArgumentEncoded=Les paramètres de ligne de commande encodés [{0}] ne correspondent pas au modèle cmdLineArgumentsEncoded configuré [{1}]
cgiServlet.invalidCommand=Un caractère illégal (''.'' or ''..'') a été trouvé dans le chemin de commande CGI, le CGI [{0}] n''est pas exécuté
+cgiServlet.noResources=Pas de ressources statiques trouvées
cgiServlet.notReady=Le Servlet CGI n'est pas prêt à fonctionner
cgiServlet.runBadHeader=Mauvaise ligne d''en-tête [{0}]
cgiServlet.runFail=Problèmes d'IO lors de l'exécution du CGI
@@ -54,6 +54,7 @@
defaultServlet.resource.size=Taille
defaultServlet.skipfail=La lecture a échouée parce que seuls [{0}] octets étaient disponibles alors qu''il était nécessaire d''en sauter [{1}] pour atteindre le début de la plage demandée
defaultServlet.unknownBomConfig=La valeur [{0}] inconnue a été donnée pour le paramètre d’initialisation useBomIfPresent
+defaultServlet.wrongByteCountForRange=Une quantité invalide d''octets [{0}] a été reçue pour la range dont la longueur est [{1}]
defaultServlet.xslError=Erreur de transformation XSL
webdavservlet.dataSourceStore.error=Erreur [{0}] lors du traitement des prorpiétés pour le chemin [{1}]
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -21,7 +21,6 @@
cgiServlet.expandCreateDirFail=スクリプトの展開先ディレクトリ[{0}]の作成に失敗しました。
cgiServlet.expandDeleteFail=拡張中にIOExceptionの後に [{0}] でファイルを削除できませんでした
cgiServlet.expandFail=パス [{0}] のスクリプトを [{1}] に展開できませんでした
-cgiServlet.expandNotFound=見つけることができなかったため [{0}] を展開できません
cgiServlet.expandOk=パス [{0}] の [{1}] に展開されたスクリプト
cgiServlet.find.found=見つかったCGI: 名前 [{0}]、パス [{1}]、スクリプト名 [{2}]、CGI名 [{3}]
cgiServlet.find.location=ファイル [{0}] を探しています。
@@ -29,6 +28,7 @@
cgiServlet.invalidArgumentDecoded=デコードされたコマンドライン引数 [{0}] は、構成されたcmdLineArgumentsDecoded パターン [{1}] にマッチしません
cgiServlet.invalidArgumentEncoded=エンコードされたコマンドライン引数 [{0}] は、構成されたcmdLineArgumentsEncoded パターン [{1}] にマッチしません
cgiServlet.invalidCommand=CGI コマンド パスに不正な文字 (''.'' または ''..'') が検出されました。CGI [{0}] は実行されていません
+cgiServlet.noResources=静的リソースが見つかりませんでした
cgiServlet.notReady=CGI サーブレットは実行の準備ができていません
cgiServlet.runBadHeader=悪いヘッダライン [{0}]
cgiServlet.runFail=CGI処理中のIO問題
@@ -54,6 +54,7 @@
defaultServlet.resource.size=サイズ
defaultServlet.skipfail=[{1}]バイトをスキップして要求された範囲の先頭に到達する必要がありましたが、[{0}]バイトしか利用できなかったため読み取りに失敗しました。
defaultServlet.unknownBomConfig=useBomIfPresentの初期化パラメーターに提供された認識されない値 [{0}]
+defaultServlet.wrongByteCountForRange=長さ [{1}] の範囲に対して無効な [{0}] バイトを受信しました
defaultServlet.xslError=XSL変換エラー
webdavservlet.dataSourceStore.error=パス [{1}] の無効なプロパティで [{0}] を処理中にエラーが発生しました
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_ko.properties tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_ko.properties
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_ko.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_ko.properties 2026-01-23 19:33:36.000000000 +0000
@@ -21,7 +21,6 @@
cgiServlet.expandCreateDirFail=스크립트를 압축해제 하기 위한 대상 디렉토리 [{0}]을(를) 생성하지 못했습니다.
cgiServlet.expandDeleteFail=압축해제 중 IOException이 발생한 후, [{0}]에 위치한 해당 파일을 삭제하지 못했습니다.
cgiServlet.expandFail=경로 [{0}]의 스크립트를 [{1}](으)로 압축해제 하지 못했습니다.
-cgiServlet.expandNotFound=[{0}]을(를) 찾을 수 없어서 압축해제 할 수 없습니다.
cgiServlet.expandOk=[{0}] 경로에 있는 스트립트가 [{1}](으)로 압축 해제되었습니다.
cgiServlet.find.found=CGI 발견: 이름 [{0}], 경로 [{1}], 스크립트 이름 [{2}], CGI 이름 [{3}]
cgiServlet.find.location=[{0}]에 위치한 파일을 찾는 중
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -17,6 +17,7 @@
# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
cgiServlet.expandFail=Невозможно развернуть скрипт [{0}] в [{1}]
+cgiServlet.find.location=Поиск файла в [{0}]
cgiServlet.runInvalidStatus=Неверный статус [{0}]
defaultServlet.skipfail=Чтение завершилось ошибкой, потому что только [{0}] байт было доступно, а требовалось пропустить [{1}] байт, чтобы достигнуть начала требуемоего диапазона
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties 2026-01-23 19:33:36.000000000 +0000
@@ -21,7 +21,6 @@
cgiServlet.expandCreateDirFail=无法为脚本扩展创建目标目录[{0}]
cgiServlet.expandDeleteFail=扩展期间,发生IOException异常后删除文件[{0}]失败
cgiServlet.expandFail=在路径[{0}] 到[{1}] 展开脚本失败.
-cgiServlet.expandNotFound=无法展开[{0}],因为找不到它。
cgiServlet.expandOk=从路径[{0}]到[{1}]扩展脚本
cgiServlet.find.found=找到CGI:name[{0}]、path[{1}]、script name[{2}]和CGI name[{3}]
cgiServlet.find.location=在 [{0}] 查找文件
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/servlets/WebdavServlet.java tomcat10-10.1.52/java/org/apache/catalina/servlets/WebdavServlet.java
--- tomcat10-10.1.40/java/org/apache/catalina/servlets/WebdavServlet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/servlets/WebdavServlet.java 2026-01-23 19:33:36.000000000 +0000
@@ -63,6 +63,7 @@
import org.apache.tomcat.util.IntrospectionUtils;
import org.apache.tomcat.util.http.ConcurrentDateFormat;
import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.Method;
import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.http.WebdavIfHeader;
import org.w3c.dom.Document;
@@ -98,6 +99,9 @@
* functionality. In particular, administrators should be aware that security constraints apply only to the request URL.
* Security constraints do not apply to any destination URL associated with the WebDAV operation (such as COPY or MOVE).
*
+ * If WebDAV functionality is included in a web application where legitimate users may access it via a browser, it is
+ * recommended that the application include CORS protection.
+ *
* To enable WebDAV for a context add the following to web.xml:
*
*
@@ -178,17 +182,6 @@
private static final long serialVersionUID = 1L;
- // -------------------------------------------------------------- Constants
-
- private static final String METHOD_PROPFIND = "PROPFIND";
- private static final String METHOD_PROPPATCH = "PROPPATCH";
- private static final String METHOD_MKCOL = "MKCOL";
- private static final String METHOD_COPY = "COPY";
- private static final String METHOD_MOVE = "MOVE";
- private static final String METHOD_LOCK = "LOCK";
- private static final String METHOD_UNLOCK = "UNLOCK";
-
-
/**
* Default lock timeout value.
*/
@@ -571,19 +564,19 @@
log("[" + method + "] " + path);
}
- if (method.equals(METHOD_PROPFIND)) {
+ if (Method.PROPFIND.equals(method)) {
doPropfind(req, resp);
- } else if (method.equals(METHOD_PROPPATCH)) {
+ } else if (Method.PROPPATCH.equals(method)) {
doProppatch(req, resp);
- } else if (method.equals(METHOD_MKCOL)) {
+ } else if (Method.MKCOL.equals(method)) {
doMkcol(req, resp);
- } else if (method.equals(METHOD_COPY)) {
+ } else if (Method.COPY.equals(method)) {
doCopy(req, resp);
- } else if (method.equals(METHOD_MOVE)) {
+ } else if (Method.MOVE.equals(method)) {
doMove(req, resp);
- } else if (method.equals(METHOD_LOCK)) {
+ } else if (Method.LOCK.equals(method)) {
doLock(req, resp);
- } else if (method.equals(METHOD_UNLOCK)) {
+ } else if (Method.UNLOCK.equals(method)) {
doUnlock(req, resp);
} else {
// DefaultServlet processing
@@ -685,6 +678,10 @@
if (hrefs.hasNext()) {
currentHref = hrefs.next();
currentPath = getPathFromHref(currentHref, request);
+ if (currentPath == null) {
+ // The path was invalid
+ return false;
+ }
currentWebResource = resources.getResource(currentPath);
} else {
break;
@@ -842,7 +839,7 @@
try (InputStream is = req.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
IOTools.flow(is, os);
body = os.toByteArray();
- } catch (IOException e) {
+ } catch (IOException ioe) {
resp.sendError(WebdavStatus.SC_BAD_REQUEST);
return;
}
@@ -1043,7 +1040,7 @@
try (InputStream is = req.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
IOTools.flow(is, os);
body = os.toByteArray();
- } catch (IOException e) {
+ } catch (IOException ioe) {
resp.sendError(WebdavStatus.SC_BAD_REQUEST);
return;
}
@@ -1241,7 +1238,11 @@
String path = getRelativePath(req);
- deleteResource(path, req, resp);
+ WebResource resource = resources.getResource(path);
+ if (!checkIfHeaders(req, resp, resource)) {
+ resp.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
+ }
+ deleteResource(path, req, resp, true);
}
@@ -1397,7 +1398,7 @@
try (InputStream is = req.getInputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
IOTools.flow(is, os);
body = os.toByteArray();
- } catch (IOException e) {
+ } catch (IOException ioe) {
resp.sendError(WebdavStatus.SC_BAD_REQUEST);
return;
}
@@ -1847,7 +1848,7 @@
if (!allowSpecialPaths) {
String upperCasePath = path.toUpperCase(Locale.ENGLISH);
return upperCasePath.startsWith("/WEB-INF/") || upperCasePath.startsWith("/META-INF/") ||
- upperCasePath.equals("/WEB-INF") || upperCasePath.equals("/META-INF");
+ upperCasePath.equals("/WEB-INF") || upperCasePath.equals("/META-INF");
}
return false;
}
@@ -1975,7 +1976,7 @@
if (parentPath == path || parentLock.depth > 0) {
if (parentLock.isExclusive()) {
return !ifHeader.contains(":" + parentLock.token + ">") ||
- (parentLock.principal != null && !parentLock.principal.equals(principal));
+ (parentLock.principal != null && !parentLock.principal.equals(principal));
} else {
for (String token : parentLock.sharedTokens) {
LockInfo lock = sharedLocks.get(token);
@@ -2260,8 +2261,8 @@
} else {
store.copy(source, dest);
}
- } catch (IOException e) {
- log(sm.getString("webdavservlet.inputstreamclosefail", source), e);
+ } catch (IOException ioe) {
+ log(sm.getString("webdavservlet.inputstreamclosefail", source), ioe);
}
} else {
errorList.put(source, Integer.valueOf(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
@@ -2274,27 +2275,6 @@
/**
* Delete a resource.
*
- * @param path Path of the resource which is to be deleted
- * @param req Servlet request
- * @param resp Servlet response
- *
- * @return true if the delete is successful
- *
- * @throws IOException If an IO error occurs
- */
- private boolean deleteResource(String path, HttpServletRequest req, HttpServletResponse resp) throws IOException {
- WebResource resource = resources.getResource(path);
- if (!checkIfHeaders(req, resp, resource)) {
- resp.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
- return false;
- }
- return deleteResource(path, req, resp, true);
- }
-
-
- /**
- * Delete a resource.
- *
* @param path Path of the resource which is to be deleted
* @param req Servlet request
* @param resp Servlet response
@@ -2752,8 +2732,8 @@
private static boolean propertyEquals(Node node1, Node node2) {
return node1.getLocalName().equals(node2.getLocalName()) &&
- ((node1.getNamespaceURI() == null && node2.getNamespaceURI() == null) ||
- (node1.getNamespaceURI() != null && node1.getNamespaceURI().equals(node2.getNamespaceURI())));
+ ((node1.getNamespaceURI() == null && node2.getNamespaceURI() == null) ||
+ (node1.getNamespaceURI() != null && node1.getNamespaceURI().equals(node2.getNamespaceURI())));
}
@@ -3045,8 +3025,6 @@
/**
* Wraps the HttpServletResponse class to abstract the specific protocol used. To support other protocols we would only
* need to modify this class and the WebDavRetCode classes.
- *
- * @author Marc Eaddy
*/
class WebdavStatus {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/Constants.java tomcat10-10.1.52/java/org/apache/catalina/session/Constants.java
--- tomcat10-10.1.40/java/org/apache/catalina/session/Constants.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/Constants.java 2026-01-23 19:33:36.000000000 +0000
@@ -23,8 +23,6 @@
/**
* Manifest constants for the org.apache.catalina.session package.
- *
- * @author Craig R. McClanahan
*/
public class Constants {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/DataSourceStore.java tomcat10-10.1.52/java/org/apache/catalina/session/DataSourceStore.java
--- tomcat10-10.1.40/java/org/apache/catalina/session/DataSourceStore.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/DataSourceStore.java 2026-01-23 19:33:36.000000000 +0000
@@ -46,8 +46,6 @@
/**
* Implementation of the {@link org.apache.catalina.Store Store} interface that stores serialized session objects in a
* database. Sessions that are saved are still subject to being expired based on inactivity.
- *
- * @author Bip Thelin
*/
public class DataSourceStore extends StoreBase {
@@ -363,7 +361,7 @@
}
}
} catch (SQLException e) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException", e));
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e);
keys = new String[0];
// Close the connection so that it gets reopened next time
} finally {
@@ -397,7 +395,7 @@
numberOfTries = 0;
}
} catch (SQLException e) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException", e));
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e);
} finally {
release(_conn);
}
@@ -444,7 +442,7 @@
numberOfTries = 0;
}
} catch (SQLException e) {
- contextLog.error(sm.getString("dataSourceStore.SQLException", e));
+ contextLog.error(sm.getString("dataSourceStore.SQLException"), e);
} finally {
context.unbind(Globals.IS_SECURITY_ENABLED, oldThreadContextCL);
release(_conn);
@@ -470,7 +468,7 @@
// Break out after the finally block
numberOfTries = 0;
} catch (SQLException e) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException", e));
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e);
} finally {
release(_conn);
}
@@ -518,7 +516,7 @@
// Break out after the finally block
numberOfTries = 0;
} catch (SQLException e) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException", e));
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e);
} finally {
release(_conn);
}
@@ -564,8 +562,8 @@
numberOfTries = 0;
}
} catch (SQLException e) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException", e));
- } catch (IOException e) {
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.SQLException"), e);
+ } catch (IOException ioe) {
// Ignore
} finally {
release(_conn);
@@ -601,7 +599,7 @@
}
}
} catch (SQLException ex) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.checkConnectionSQLException", ex));
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.checkConnectionSQLException"), ex);
}
return conn;
@@ -686,7 +684,7 @@
try {
dbConnection.close();
} catch (SQLException e) {
- manager.getContext().getLogger().error(sm.getString("dataSourceStore.close", e));
+ manager.getContext().getLogger().error(sm.getString("dataSourceStore.close"), e);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/FileStore.java tomcat10-10.1.52/java/org/apache/catalina/session/FileStore.java
--- tomcat10-10.1.40/java/org/apache/catalina/session/FileStore.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/FileStore.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,6 +26,7 @@
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.locks.Lock;
import jakarta.servlet.ServletContext;
@@ -34,13 +35,12 @@
import org.apache.catalina.Session;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.concurrent.KeyedReentrantReadWriteLock;
import org.apache.tomcat.util.res.StringManager;
/**
* Concrete implementation of the Store interface that utilizes a file per saved Session in a configured
* directory. Sessions that are saved are still subject to being expired based on inactivity.
- *
- * @author Craig R. McClanahan
*/
public final class FileStore extends StoreBase {
@@ -62,7 +62,7 @@
* The pathname of the directory in which Sessions are stored. This may be an absolute pathname, or a relative path
* that is resolved against the temporary work directory for this application.
*/
- private String directory = ".";
+ private volatile String directory = ".";
/**
@@ -70,6 +70,7 @@
*/
private File directoryFile = null;
+ private KeyedReentrantReadWriteLock sessionLocksById = new KeyedReentrantReadWriteLock();
/**
* Name to register for this Store, used for logging.
@@ -98,7 +99,7 @@
*
* @param path The new directory path
*/
- public void setDirectory(String path) {
+ public synchronized void setDirectory(String path) {
String oldDirectory = this.directory;
this.directory = path;
this.directoryFile = null;
@@ -183,7 +184,7 @@
public Session load(String id) throws ClassNotFoundException, IOException {
// Open an input stream to the specified pathname, if any
File file = file(id);
- if (file == null || !file.exists()) {
+ if (file == null) {
return null;
}
@@ -195,19 +196,28 @@
}
ClassLoader oldThreadContextCL = context.bind(Globals.IS_SECURITY_ENABLED, null);
-
- try (FileInputStream fis = new FileInputStream(file.getAbsolutePath());
- ObjectInputStream ois = getObjectInputStream(fis)) {
-
- StandardSession session = (StandardSession) manager.createEmptySession();
- session.readObjectData(ois);
- session.setManager(manager);
- return session;
- } catch (FileNotFoundException e) {
- if (contextLog.isDebugEnabled()) {
- contextLog.debug(sm.getString("fileStore.noFile", id, file.getAbsolutePath()));
+ try {
+ Lock readLock = sessionLocksById.getLock(id).readLock();
+ readLock.lock();
+ try {
+ if (!file.exists()) {
+ return null;
+ }
+ try (FileInputStream fis = new FileInputStream(file.getAbsolutePath());
+ ObjectInputStream ois = getObjectInputStream(fis)) {
+ StandardSession session = (StandardSession) manager.createEmptySession();
+ session.readObjectData(ois);
+ session.setManager(manager);
+ return session;
+ } catch (FileNotFoundException e) {
+ if (contextLog.isDebugEnabled()) {
+ contextLog.debug(sm.getString("fileStore.noFile", id, file.getAbsolutePath()), e);
+ }
+ return null;
+ }
+ } finally {
+ readLock.unlock();
}
- return null;
} finally {
context.unbind(Globals.IS_SECURITY_ENABLED, oldThreadContextCL);
}
@@ -225,8 +235,14 @@
.trace(sm.getString(getStoreName() + ".removing", id, file.getAbsolutePath()));
}
- if (file.exists() && !file.delete()) {
- throw new IOException(sm.getString("fileStore.deleteSessionFailed", file));
+ Lock writeLock = sessionLocksById.getLock(id).writeLock();
+ writeLock.lock();
+ try {
+ if (file.exists() && !file.delete()) {
+ throw new IOException(sm.getString("fileStore.deleteSessionFailed", file));
+ }
+ } finally {
+ writeLock.unlock();
}
}
@@ -243,9 +259,15 @@
.trace(sm.getString(getStoreName() + ".saving", session.getIdInternal(), file.getAbsolutePath()));
}
- try (FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());
- ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos))) {
- ((StandardSession) session).writeObjectData(oos);
+ Lock writeLock = sessionLocksById.getLock(session.getIdInternal()).writeLock();
+ writeLock.lock();
+ try {
+ try (FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());
+ ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos))) {
+ ((StandardSession) session).writeObjectData(oos);
+ }
+ } finally {
+ writeLock.unlock();
}
}
@@ -256,12 +278,12 @@
* Return a File object representing the pathname to our session persistence directory, if any. The directory will
* be created if it does not already exist.
*/
- private File directory() throws IOException {
+ private synchronized File directory() throws IOException {
+ // Synchronised to avoid concurrent attempts to create the directory.
if (this.directory == null) {
return null;
}
if (this.directoryFile != null) {
- // NOTE: Race condition is harmless, so do not synchronize
return this.directoryFile;
}
File file = new File(this.directory);
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings.properties tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -16,11 +16,11 @@
# Do not edit this file directly.
# To edit translations see: https://tomcat.apache.org/getinvolved.html#Translations
-dataSourceStore.SQLException=SQL Error [{0}]
+dataSourceStore.SQLException=SQL Error
dataSourceStore.checkConnectionDBClosed=The database connection is null or was found to be closed. Trying to re-open it.
dataSourceStore.checkConnectionDBReOpenFail=The re-open on the database failed. The database could be down.
-dataSourceStore.checkConnectionSQLException=A SQL exception occurred [{0}]
-dataSourceStore.close=Exception closing database connection [{0}]
+dataSourceStore.checkConnectionSQLException=A SQL exception occurred checking the connection
+dataSourceStore.close=Exception closing database connection
dataSourceStore.commitSQLException=SQLException committing connection before closing
dataSourceStore.loading=Loading Session [{0}] from database [{1}]
dataSourceStore.missingDataSource=No data source available
@@ -54,7 +54,7 @@
persistentManager.loading=Loading [{0}] persisted sessions
persistentManager.noStore=No Store configured, persistence disabled
persistentManager.removeError=Error removing session [{0}] from the store
-persistentManager.serializeError=Error serializing Session [{0}]: [{1}]
+persistentManager.serializeError=Error serializing Session [{0}]
persistentManager.storeClearError=Error clearning all sessions from the store
persistentManager.storeKeysException=Unable to determine the list of session IDs for sessions in the session store, assuming that the store is empty
persistentManager.storeLoadError=Error swapping in sessions from the store
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_es.properties tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_es.properties
--- tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_es.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_es.properties 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,8 @@
dataSourceStore.SQLException=Error SQL [{0}]
dataSourceStore.checkConnectionDBClosed=La conexióna a base de datos es nula o está cerrada. Intentando reabrirla.
dataSourceStore.checkConnectionDBReOpenFail=Falló la reapertura de la base de datos. Puede que la base de datos esté caída.
-dataSourceStore.checkConnectionSQLException=Ha tenido lugar una excepción SQL [{0}]
-dataSourceStore.close=Excepción cerrando conexión a base de datos [{0}]
+dataSourceStore.checkConnectionSQLException=Ha tenido lugar una excepción SQL
+dataSourceStore.close=Excepción cerrando conexión a base de datos
dataSourceStore.loading=Cargando Sesión [{0}] desde base de datos [{1}]
dataSourceStore.missingDataSourceName=No se proporcionó un nombre JNDI válido
dataSourceStore.removing=Quitando Sesión [{0}] en base de datos [{1}]
@@ -38,7 +38,7 @@
persistentManager.backupMaxIdle=Respaldando sesión [{0}] a Almacén, ociosa durante [{1}] segundos
persistentManager.deserializeError=Error des-serializando Sesión [{0}]: [{1}]
persistentManager.loading=Cargando [{0}] sesiones persistidas
-persistentManager.serializeError=Error serializando Sesión [{0}]: [{1}]
+persistentManager.serializeError=Error serializando Sesión [{0}]
persistentManager.storeKeysException=Imposible determinar la lista de IDs de sesiones en la tienda de sesiones, asumiendo que la tienda esta vacia
persistentManager.storeSizeException=No se puede determinar el numero de sesiones en el almacenamiento de sesiones, asumiendo que el almacenamiento esta vacío
persistentManager.swapIn=Intercambiando sesión [{0}] a dentro desde Almacén
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_fr.properties tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_fr.properties
--- tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_fr.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_fr.properties 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,8 @@
dataSourceStore.SQLException=Erreur SQL [{0}]
dataSourceStore.checkConnectionDBClosed=La connexion à la base de données est nulle ou a été trouvée fermée. Tentative de réouverture.
dataSourceStore.checkConnectionDBReOpenFail=La tentative de réouverture de la base de données a échoué. La base de données est peut-être arrêtée.
-dataSourceStore.checkConnectionSQLException=Une exception SQL s''est produite [{0}]
-dataSourceStore.close=Exception lors de la fermeture de la connection vers la base de donnée [{0}]
+dataSourceStore.checkConnectionSQLException=Une exception SQL s'est produite
+dataSourceStore.close=Exception lors de la fermeture de la connection vers la base de donnée
dataSourceStore.commitSQLException=Une SQLException a été retournée lors du commit de la connection avant sa fermeture
dataSourceStore.loading=Chargement de la Session [{0}] depuis la base de données [{1}]
dataSourceStore.missingDataSource=Aucune source de données n'est disponible
@@ -54,7 +54,7 @@
persistentManager.loading=Chargement de [{0}] sessions persistantes
persistentManager.noStore=Aucun stockage (Store) n'a été configuré, la persistence est désactivée
persistentManager.removeError=Erreur en enlevant la session [{0}] du stockage
-persistentManager.serializeError=Erreur lors de la sérialisation de la session [{0}] : [{1}]
+persistentManager.serializeError=Erreur lors de la sérialisation de la session [{0}]
persistentManager.storeClearError=Erreur en supprimant toutes les sessions du stockage
persistentManager.storeKeysException=Incapacité de déterminer la liste des ID de session, pour les sessions dans le magasin de sessions. Supposant le magasin vide.
persistentManager.storeLoadError=Erreur en déplaçant les sessions à partir du stockage
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,8 @@
dataSourceStore.SQLException=SQLエラー [{0}]
dataSourceStore.checkConnectionDBClosed=データベース接続がnullであるか、クローズされているのが見つかりました。再オープンしてください。
dataSourceStore.checkConnectionDBReOpenFail=データベースの再オープンが失敗しました。データベースがダウンしているかもしれません。
-dataSourceStore.checkConnectionSQLException=SQL例外が発生しました [{0}]
-dataSourceStore.close=データベース接続 [{0}] をクローズ中の例外です
+dataSourceStore.checkConnectionSQLException=SQL例外が発生しました
+dataSourceStore.close=データベース接続 をクローズ中の例外です
dataSourceStore.commitSQLException=クローズ前のデータベース接続のコミット中にSQL例外が発生しました
dataSourceStore.loading=セッション [{0}] をデータベース [{1}] からロードします
dataSourceStore.missingDataSource=利用可能なデータソースがありません
@@ -54,7 +54,7 @@
persistentManager.loading=[{0}] の永続化セッションをロードします
persistentManager.noStore=ストアが構成されておらず、永続性が無効になっています
persistentManager.removeError=ストアからセッション[{0}]削除中のエラー
-persistentManager.serializeError=セッション [{0}] をシリアライズ中のエラーです: [{1}]
+persistentManager.serializeError=セッション [{0}] をシリアライズ中のエラーです
persistentManager.storeClearError=ストア上の全セッション消去中のエラー
persistentManager.storeKeysException=セッションストアからセッションIDのリストを取得できませんでした。セッションストアが空の可能性があります
persistentManager.storeLoadError=ストアからのセッションスワップイン中のエラー
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_ko.properties tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_ko.properties
--- tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_ko.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_ko.properties 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,8 @@
dataSourceStore.SQLException=SQL 오류 [{0}]
dataSourceStore.checkConnectionDBClosed=데이터베이스 연결이 널이거나 닫힌 상태입니다. 다시 열려고 시도합니다.
dataSourceStore.checkConnectionDBReOpenFail=데이터베이스에 대해 다시 연결을 맺지 못했습니다. 데이터베이스가 다운되었을 수 있습니다.
-dataSourceStore.checkConnectionSQLException=SQL 예외 발생 [{0}]
-dataSourceStore.close=데이터베이스 연결 [{0}]을(를) 닫는 동안 예외 발생
+dataSourceStore.checkConnectionSQLException=SQL 예외 발생
+dataSourceStore.close=데이터베이스 연결을(를) 닫는 동안 예외 발생
dataSourceStore.commitSQLException=데이터베이스 연결을 닫기 전, 커밋을 시도하는 중 SQLException 발생
dataSourceStore.loading=데이터베이스 [{1}](으)로부터 세션 [{0}]을(를) 로드합니다.
dataSourceStore.missingDataSource=DataSource를 사용할 수 없습니다.
@@ -51,7 +51,7 @@
persistentManager.isLoadedError=세션 [{0}]이(가) 메모리에 로드되었는지 점검 중 오류 발생
persistentManager.loading=[{0}]개의 저장된 세션들을 로드합니다.
persistentManager.removeError=세션 [{0}]을(를) 저장소로부터 제거하는 중 오류 발생
-persistentManager.serializeError=세션을 직렬화하는 중 오류 발생 [{0}]: [{1}]
+persistentManager.serializeError=세션을 직렬화하는 중 오류 발생 [{0}]
persistentManager.storeClearError=저장소로부터 모든 세션들을 해제하는 중 오류 발생
persistentManager.storeKeysException=세션 저장소에 있는 세션들의 ID 목록을 결정할 수 없습니다. 아마도 세션 저장소가 비어 있는 것 같습니다.
persistentManager.storeLoadError=저장소로부터 세션들을 메모리로 로드하는 중 오류 발생
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_zh_CN.properties tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_zh_CN.properties
--- tomcat10-10.1.40/java/org/apache/catalina/session/LocalStrings_zh_CN.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/LocalStrings_zh_CN.properties 2026-01-23 19:33:36.000000000 +0000
@@ -19,8 +19,8 @@
dataSourceStore.SQLException=SQL错误[{0}]
dataSourceStore.checkConnectionDBClosed=数据库连接为空或已关闭。正在尝试重新连接。
dataSourceStore.checkConnectionDBReOpenFail=重新打开数据库失败,数据库可能已经宕机。
-dataSourceStore.checkConnectionSQLException=发生 SQL 异常 [{0}]
-dataSourceStore.close=关闭数据库连接[{0}]时发生异常
+dataSourceStore.checkConnectionSQLException=发生 SQL 异常
+dataSourceStore.close=关闭数据库连接时发生异常
dataSourceStore.commitSQLException=关闭前提交连接的SQLException
dataSourceStore.loading=正在从数据库[{1}]加载会话[{0}]
dataSourceStore.missingDataSource=没有可用的数据源
@@ -51,7 +51,7 @@
persistentManager.isLoadedError=检查内存中是否加载了会话[{0}]时出错
persistentManager.loading=正在加载[{0}]持久化会话
persistentManager.removeError=从存储中删除会话[{0}]时出错
-persistentManager.serializeError=错误的序列化会话 [{0}]:[{1}]
+persistentManager.serializeError=错误的序列化会话 [{0}]
persistentManager.storeClearError=清除存储区中的所有会话时出错
persistentManager.storeKeysException=不能从 session存储中获取session ID 的列表,假设存储为空
persistentManager.storeLoadError=从存储区交换会话时出错
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/ManagerBase.java tomcat10-10.1.52/java/org/apache/catalina/session/ManagerBase.java
--- tomcat10-10.1.40/java/org/apache/catalina/session/ManagerBase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/ManagerBase.java 2026-01-23 19:33:36.000000000 +0000
@@ -55,8 +55,6 @@
/**
* Minimal implementation of the Manager interface that supports no session persistence or distributable
* capabilities. This class may be subclassed to create more sophisticated Manager implementations.
- *
- * @author Craig R. McClanahan
*/
public abstract class ManagerBase extends LifecycleMBeanBase implements Manager {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/PersistentManager.java tomcat10-10.1.52/java/org/apache/catalina/session/PersistentManager.java
--- tomcat10-10.1.40/java/org/apache/catalina/session/PersistentManager.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/PersistentManager.java 2026-01-23 19:33:36.000000000 +0000
@@ -26,8 +26,6 @@
*
* If used with a load-balancer, the load-balancer must be configured to use sticky sessions for this manager to operate
* correctly.
- *
- * @author Kief Morris (kief@kief.com)
*/
public final class PersistentManager extends PersistentManagerBase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/session/PersistentManagerBase.java tomcat10-10.1.52/java/org/apache/catalina/session/PersistentManagerBase.java
--- tomcat10-10.1.40/java/org/apache/catalina/session/PersistentManagerBase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/session/PersistentManagerBase.java 2026-01-23 19:33:36.000000000 +0000
@@ -42,8 +42,6 @@
*
ClassLoader instance that should become the parent of the new class loader.
*
- *
- * @author Craig R. McClanahan
*/
public final class ClassLoaderFactory {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/Constants.java tomcat10-10.1.52/java/org/apache/catalina/startup/Constants.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/Constants.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/Constants.java 2026-01-23 19:33:36.000000000 +0000
@@ -20,8 +20,6 @@
* String constants for the startup package.
* Note that some values include a leading '/' and that some do not. This is intentional based on how the values are
* used.
- *
- * @author Craig R. McClanahan
*/
public final class Constants {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/ContextConfig.java tomcat10-10.1.52/java/org/apache/catalina/startup/ContextConfig.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/ContextConfig.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/ContextConfig.java 2026-01-23 19:33:36.000000000 +0000
@@ -118,8 +118,6 @@
/**
* Startup event listener for a Context that configures the properties of that Context, and the associated
* defined servlets.
- *
- * @author Craig R. McClanahan
*/
public class ContextConfig implements LifecycleListener {
@@ -604,8 +602,8 @@
}
} catch (MalformedURLException e) {
log.error(sm.getString("contextConfig.badUrl", defaultContextXml), e);
- } catch (IOException e) {
- // Not found
+ } catch (IOException ignore) {
+ // Ignore - Not found
}
}
@@ -646,8 +644,8 @@
}
} catch (MalformedURLException e) {
log.error(sm.getString("contextConfig.badUrl", hostContextFile), e);
- } catch (IOException e) {
- // Not found
+ } catch (IOException ignore) {
+ // Ignore - Not found
}
}
}
@@ -678,7 +676,7 @@
generateClassFooter(digester);
try (FileWriter writer = new FileWriter(contextXmlJavaSource)) {
writer.write(digester.getGeneratedCode().toString());
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
digester.endGeneratingCode();
@@ -739,7 +737,8 @@
}
} catch (SAXParseException e) {
log.error(sm.getString("contextConfig.contextParse", context.getName()), e);
- log.error(sm.getString("contextConfig.defaultPosition", "" + e.getLineNumber(), "" + e.getColumnNumber()));
+ log.error(sm.getString("contextConfig.defaultPosition", Integer.toString(e.getLineNumber()),
+ Integer.toString(e.getColumnNumber())));
ok = false;
} catch (Exception e) {
log.error(sm.getString("contextConfig.contextParse", context.getName()), e);
@@ -749,8 +748,8 @@
if (stream != null) {
stream.close();
}
- } catch (IOException e) {
- log.error(sm.getString("contextConfig.contextClose"), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("contextConfig.contextClose"), ioe);
}
}
}
@@ -946,8 +945,8 @@
try {
fixDocBase();
- } catch (IOException e) {
- log.error(sm.getString("contextConfig.fixDocBase", context.getName()), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("contextConfig.fixDocBase", context.getName()), ioe);
}
antiLocking();
@@ -1621,8 +1620,8 @@
if (uc != null) {
try {
uc.getInputStream().close();
- } catch (IOException e) {
- ExceptionUtils.handleThrowable(e);
+ } catch (IOException ioe) {
+ ExceptionUtils.handleThrowable(ioe);
globalTimeStamp = -1;
}
}
@@ -1642,8 +1641,8 @@
if (uc != null) {
try {
uc.getInputStream().close();
- } catch (IOException e) {
- ExceptionUtils.handleThrowable(e);
+ } catch (IOException ioe) {
+ ExceptionUtils.handleThrowable(ioe);
hostTimeStamp = -1;
}
}
@@ -1764,8 +1763,8 @@
try {
WebappServiceLoader loader = new WebappServiceLoader<>(context);
detectedScis = loader.load(ServletContainerInitializer.class);
- } catch (IOException e) {
- log.error(sm.getString("contextConfig.servletContainerInitializerFail", context.getName()), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("contextConfig.servletContainerInitializerFail", context.getName()), ioe);
ok = false;
return;
}
@@ -1778,7 +1777,7 @@
ht = sci.getClass().getAnnotation(HandlesTypes.class);
} catch (Exception e) {
if (log.isDebugEnabled()) {
- log.info(sm.getString("contextConfig.sci.debug", sci.getClass().getName()), e);
+ log.debug(sm.getString("contextConfig.sci.debug", sci.getClass().getName()), e);
} else {
log.info(sm.getString("contextConfig.sci.info", sci.getClass().getName()));
}
@@ -1928,7 +1927,7 @@
if (source == null && stream != null) {
try {
stream.close();
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore
}
}
@@ -1979,7 +1978,7 @@
String hostWebXml = Container.getConfigPath(context, Constants.HostWebXml);
webXmlResource = ConfigFileLoader.getSource().getResource(hostWebXml);
}
- } catch (IOException e) {
+ } catch (IOException ignore) {
// Ignore if not found
return null;
}
@@ -1999,7 +1998,7 @@
if (source == null && stream != null) {
try {
stream.close();
- } catch (IOException e) {
+ } catch (IOException ioe) {
// Ignore
}
}
@@ -2198,8 +2197,8 @@
jar.nextEntry();
entryName = jar.getEntryName();
}
- } catch (IOException e) {
- log.error(sm.getString("contextConfig.jarFile", url), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("contextConfig.jarFile", url), ioe);
}
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/ContextRuleSet.java tomcat10-10.1.52/java/org/apache/catalina/startup/ContextRuleSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/ContextRuleSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/ContextRuleSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,8 +21,6 @@
/**
* RuleSet for processing the contents of a Context definition element.
- *
- * @author Craig R. McClanahan
*/
public class ContextRuleSet implements RuleSet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java tomcat10-10.1.52/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java 2026-01-23 19:33:36.000000000 +0000
@@ -27,8 +27,6 @@
/**
* Rule that copies the parentClassLoader property from the next-to-top item on the stack (which must be a
* Container) to the top item on the stack (which must also be a Container).
- *
- * @author Craig R. McClanahan
*/
public class CopyParentClassLoaderRule extends Rule {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/EngineConfig.java tomcat10-10.1.52/java/org/apache/catalina/startup/EngineConfig.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/EngineConfig.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/EngineConfig.java 2026-01-23 19:33:36.000000000 +0000
@@ -29,8 +29,6 @@
/**
* Startup event listener for an Engine that configures the properties of that Engine, and the associated defined
* contexts.
- *
- * @author Craig R. McClanahan
*/
public class EngineConfig implements LifecycleListener {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/EngineRuleSet.java tomcat10-10.1.52/java/org/apache/catalina/startup/EngineRuleSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/EngineRuleSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/EngineRuleSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -22,8 +22,6 @@
/**
* RuleSet for processing the contents of an Engine definition element. This RuleSet does
* NOT include any rules for nested Host elements, which should be added via instances of HostRuleSet.
- *
- * @author Craig R. McClanahan
*/
public class EngineRuleSet implements RuleSet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/ExpandWar.java tomcat10-10.1.52/java/org/apache/catalina/startup/ExpandWar.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/ExpandWar.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/ExpandWar.java 2026-01-23 19:33:36.000000000 +0000
@@ -40,10 +40,6 @@
/**
* Expand out a WAR in a Host's appBase.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- * @author Glenn L. Nielsen
*/
public class ExpandWar {
@@ -262,8 +258,8 @@
throw new EOFException();
}
}
- } catch (IOException e) {
- log.error(sm.getString("expandWar.copy", fileSrc, fileDest), e);
+ } catch (IOException ioe) {
+ log.error(sm.getString("expandWar.copy", fileSrc, fileDest), ioe);
result = false;
}
}
@@ -273,8 +269,8 @@
/**
- * Delete the specified directory, including all of its contents and subdirectories recursively. Any failure will
- * be logged.
+ * Delete the specified directory, including all of its contents and subdirectories recursively. Any failure will be
+ * logged.
*
* @param dir File object representing the directory to be deleted
*
@@ -313,8 +309,8 @@
/**
- * Delete the specified directory, including all of its contents and subdirectories recursively. Any failure will
- * be logged.
+ * Delete the specified directory, including all of its contents and subdirectories recursively. Any failure will be
+ * logged.
*
* @param dir File object representing the directory to be deleted
*
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/FailedContext.java tomcat10-10.1.52/java/org/apache/catalina/startup/FailedContext.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/FailedContext.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/FailedContext.java 2026-01-23 19:33:36.000000000 +0000
@@ -1431,4 +1431,15 @@
public void setSuspendWrappedResponseAfterForward(boolean suspendWrappedResponseAfterForward) {
}
+ public long getStartTime() {
+ return -1;
+ }
+
+ public long getStartupTime() {
+ return -1;
+ }
+
+ public long getTldScanTime() {
+ return -1;
+ }
}
\ No newline at end of file
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/HomesUserDatabase.java tomcat10-10.1.52/java/org/apache/catalina/startup/HomesUserDatabase.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/HomesUserDatabase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/HomesUserDatabase.java 2026-01-23 19:33:36.000000000 +0000
@@ -25,8 +25,6 @@
/**
* Concrete implementation of the UserDatabase interface considers all directories in a directory whose
* pathname is specified to our constructor to be "home" directories for those users.
- *
- * @author Craig R. McClanahan
*/
public final class HomesUserDatabase implements UserDatabase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/HostConfig.java tomcat10-10.1.52/java/org/apache/catalina/startup/HostConfig.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/HostConfig.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/HostConfig.java 2026-01-23 19:33:36.000000000 +0000
@@ -77,9 +77,6 @@
/**
* Startup event listener for a Host that configures the properties of that Host, and the associated defined
* contexts.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class HostConfig implements LifecycleListener {
@@ -389,7 +386,7 @@
}
try {
return file.getCanonicalFile();
- } catch (IOException e) {
+ } catch (IOException ioe) {
return file;
}
}
@@ -840,14 +837,15 @@
if (entry != null) {
xmlInWar = true;
}
- } catch (IOException e) {
- /* Ignore */
+ } catch (IOException ignore) {
+ // Ignore
}
// If there is an expanded directory then any xml in that directory
// should only be used if the directory is not out of date and
// unpackWARs is true. Note the code below may apply further limits
- boolean useXml = xml.exists() && unpackWARs && (!warTracker.exists() || warTracker.lastModified() == war.lastModified());
+ boolean useXml =
+ xml.exists() && unpackWARs && (!warTracker.exists() || warTracker.lastModified() == war.lastModified());
// If the xml file exists then expandedDir must exist so no need to
// test that here
@@ -924,8 +922,8 @@
OutputStream ostream = new FileOutputStream(xml)) {
IOTools.flow(istream, ostream);
}
- } catch (IOException e) {
- /* Ignore */
+ } catch (IOException ignore) {
+ // Ignore
}
}
}
@@ -1549,16 +1547,16 @@
String canonicalLocation;
try {
canonicalLocation = resource.getParentFile().getCanonicalPath();
- } catch (IOException e) {
- log.warn(sm.getString("hostConfig.canonicalizing", resource.getParentFile(), app.name), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("hostConfig.canonicalizing", resource.getParentFile(), app.name), ioe);
return false;
}
String canonicalAppBase;
try {
canonicalAppBase = host.getAppBaseFile().getCanonicalPath();
- } catch (IOException e) {
- log.warn(sm.getString("hostConfig.canonicalizing", host.getAppBaseFile(), app.name), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("hostConfig.canonicalizing", host.getAppBaseFile(), app.name), ioe);
return false;
}
@@ -1570,8 +1568,8 @@
String canonicalConfigBase;
try {
canonicalConfigBase = host.getConfigBaseFile().getCanonicalPath();
- } catch (IOException e) {
- log.warn(sm.getString("hostConfig.canonicalizing", host.getConfigBaseFile(), app.name), e);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("hostConfig.canonicalizing", host.getConfigBaseFile(), app.name), ioe);
return false;
}
@@ -1955,14 +1953,14 @@
/*
- * The purpose of this class is to provide a way for HostConfig to get a Context to delete an expanded WAR after the
- * Context stops. This is to resolve this issue described in Bug 57772. The alternative solutions require either
- * duplicating a lot of the Context.reload() code in HostConfig or adding a new reload(boolean) method to Context
- * that allows the caller to optionally delete any expanded WAR.
- *
- * The LifecycleListener approach offers greater flexibility and enables the behaviour to be changed / extended /
- * removed in future without changing the Context API.
- */
+ * The purpose of this class is to provide a way for HostConfig to get a Context to delete an expanded WAR after the
+ * Context stops. This is to resolve this issue described in Bug 57772. The alternative solutions require either
+ * duplicating a lot of the Context.reload() code in HostConfig or adding a new reload(boolean) method to Context
+ * that allows the caller to optionally delete any expanded WAR.
+ *
+ * The LifecycleListener approach offers greater flexibility and enables the behaviour to be changed / extended /
+ * removed in future without changing the Context API.
+ */
private static class ExpandedDirectoryRemovalListener implements LifecycleListener {
private final File toDelete;
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/HostRuleSet.java tomcat10-10.1.52/java/org/apache/catalina/startup/HostRuleSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/HostRuleSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/HostRuleSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -22,8 +22,6 @@
/**
* RuleSet for processing the contents of a Host definition element. This RuleSet does NOT
* include any rules for nested Context which should be added via instances of ContextRuleSet.
- *
- * @author Craig R. McClanahan
*/
public class HostRuleSet implements RuleSet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/ListenerCreateRule.java tomcat10-10.1.52/java/org/apache/catalina/startup/ListenerCreateRule.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/ListenerCreateRule.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/ListenerCreateRule.java 2026-01-23 19:33:36.000000000 +0000
@@ -49,7 +49,7 @@
} catch (Exception e) {
String className = getRealClassName(attributes);
if (log.isDebugEnabled()) {
- log.info(sm.getString("listener.createFailed", className), e);
+ log.debug(sm.getString("listener.createFailed", className), e);
} else {
log.info(sm.getString("listener.createFailed", className));
}
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/LocalStrings_ja.properties tomcat10-10.1.52/java/org/apache/catalina/startup/LocalStrings_ja.properties
--- tomcat10-10.1.40/java/org/apache/catalina/startup/LocalStrings_ja.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/LocalStrings_ja.properties 2026-01-23 19:33:36.000000000 +0000
@@ -153,7 +153,7 @@
hostConfig.migrateError=マイグレーション失敗
hostConfig.reload=リロード中のコンテキスト [{0}]
hostConfig.resourceNotAbsolute=[{1}] は完全パスではないためコンテキスト [{0}] からリソースを削除できません
-hostConfig.start=HostConfig: 処理を停止します
+hostConfig.start=HostConfig: 処理を開始します
hostConfig.stop=HostConfig: 処理を停止します
hostConfig.undeploy=コンテキストパス [{0}] のWebアプリケーションの配備を解除します
hostConfig.undeployVersion=コンテキスト [{0}] について有効なセッションの存在しない古いバージョンの配備を解除します。
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/LocalStrings_ru.properties tomcat10-10.1.52/java/org/apache/catalina/startup/LocalStrings_ru.properties
--- tomcat10-10.1.40/java/org/apache/catalina/startup/LocalStrings_ru.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/LocalStrings_ru.properties 2026-01-23 19:33:36.000000000 +0000
@@ -24,8 +24,12 @@
contextConfig.defaultMissing=Не обнаружен глобальный web.xml
contextConfig.defaultPosition=Произошло в строке [{0}] столбце [{1}]
contextConfig.inputStreamWebResource=Не возможно обработать веб ресурс [{0}] для аннотаций\n
+contextConfig.jspFile.error=JSP файл [{0}] должен начинаться с ''/''
+contextConfig.processAnnotationsDir.debug=Сканируется директория в поисках файлов классов с аннотациями [{0}]
contextConfig.tomcatWebXmlError=Ошибка обработки /WEB-INF/tomcat-web.xml
+expandWar.createFailed=Невозможно создать директорию [{0}]
+
hostConfig.deployDir=Установка веб приложения в папку [{0}]
hostConfig.deployWar.error=Ошибка при развертывании архива с веб-приложением [{0}]
hostConfig.docBaseUrlInvalid=Предоставленый docBase не может быть представлен в виде URL
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties tomcat10-10.1.52/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
--- tomcat10-10.1.40/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties 2026-01-23 19:33:36.000000000 +0000
@@ -127,7 +127,7 @@
hostConfig.deployDir.finished=Web应用程序目录[{0}]的部署已在[{1}]毫秒内完成
hostConfig.deployDir.threaded.error=等待目录的多线程部署完成时出错
hostConfig.deployWar=正在部署web应用程序存档文件[{0}]
-hostConfig.deployWar.error=部署 Web 应用程序 archive [{0}] 时出错
+hostConfig.deployWar.error=部署 Web 应用程序存档 [{0}] 时出错
hostConfig.deployWar.finished=web应用程序存档文件[{0}]的部署已在[{1}]ms内完成
hostConfig.deployWar.hiddenDir=将忽略目录[{0}],因为WAR [{1}]优先,unpackWAR为false
hostConfig.deployWar.threaded.error=等待WAR文件的多线程部署完成时出错
@@ -163,7 +163,7 @@
tomcat.noContextClass=无法为主机[{1}]和url[{2}]实例化上下文类[{0}]
tomcat.noContextXml=不能找到web 应用的context.xml [{0}]
-userConfig.database=加载用户数据库异常
+userConfig.database=用户数据库加载异常
userConfig.deploy=正在为用户[{0}]部署web应用程序
userConfig.deploy.threaded.error=等待用户目录的多线程部署完成时出错
userConfig.deploying=正在部署用户 web 应用程序
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/MimeTypeMappings.properties tomcat10-10.1.52/java/org/apache/catalina/startup/MimeTypeMappings.properties
--- tomcat10-10.1.40/java/org/apache/catalina/startup/MimeTypeMappings.properties 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/MimeTypeMappings.properties 2026-01-23 19:33:36.000000000 +0000
@@ -62,6 +62,7 @@
atx=application/vnd.antix.game-component
au=audio/basic
avi=video/x-msvideo
+avif=image/avif
avx=video/x-rad-screenplay
aw=application/applixware
axa=audio/annodex
@@ -388,6 +389,7 @@
json=application/json
jsonml=application/jsonml+json
jspf=text/plain
+jxl=image/jxl
kar=audio/midi
karbon=application/vnd.kde.karbon
kfo=application/vnd.kde.kformula
@@ -430,6 +432,8 @@
m1v=video/mpeg
m21=application/mp21
m2a=audio/mpeg
+m2t=video/mp2t
+m2ts=video/mp2t
m2v=video/mpeg
m3a=audio/mpeg
m3u=audio/x-mpegurl
@@ -522,7 +526,7 @@
msi=application/x-msdownload
msl=application/vnd.mobius.msl
msty=application/vnd.muvee.style
-mts=model/vnd.mts
+mts=video/mp2t
mus=application/vnd.musician
musicxml=application/vnd.recordare.musicxml+xml
mvb=application/x-msmediaview
@@ -777,6 +781,8 @@
spq=application/scvp-vp-request
spx=audio/ogg
sql=application/x-sql
+sqlite=application/vnd.sqlite3
+sqlite3=application/vnd.sqlite3
src=application/x-wais-source
srt=application/x-subrip
sru=application/sru+xml
@@ -839,6 +845,7 @@
tr=text/troff
tra=application/vnd.trueapp
trm=application/x-msterminal
+ts=video/mp2t
tsd=application/timestamped-data
tsv=text/tab-separated-values
ttc=font/collection
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/NamingRuleSet.java tomcat10-10.1.52/java/org/apache/catalina/startup/NamingRuleSet.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/NamingRuleSet.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/NamingRuleSet.java 2026-01-23 19:33:36.000000000 +0000
@@ -21,9 +21,6 @@
/**
* RuleSet for processing the JNDI Enterprise Naming Context resource declaration elements.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
*/
public class NamingRuleSet implements RuleSet {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/PasswdUserDatabase.java tomcat10-10.1.52/java/org/apache/catalina/startup/PasswdUserDatabase.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/PasswdUserDatabase.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/PasswdUserDatabase.java 2026-01-23 19:33:36.000000000 +0000
@@ -30,8 +30,6 @@
/**
* Concrete implementation of the UserDatabase interface that processes the /etc/passwd file
* on a Unix system.
- *
- * @author Craig R. McClanahan
*/
public final class PasswdUserDatabase implements UserDatabase {
diff -Nru tomcat10-10.1.40/java/org/apache/catalina/startup/Tomcat.java tomcat10-10.1.52/java/org/apache/catalina/startup/Tomcat.java
--- tomcat10-10.1.40/java/org/apache/catalina/startup/Tomcat.java 2025-04-01 18:12:59.000000000 +0000
+++ tomcat10-10.1.52/java/org/apache/catalina/startup/Tomcat.java 2026-01-23 19:33:36.000000000 +0000
@@ -132,8 +132,6 @@
*
* @see TestTomcat
- *
- * @author Costin Manolache
*/
public class Tomcat {
@@ -812,7 +810,7 @@
}
try {
baseFile = baseFile.getCanonicalFile();
- } catch (IOException e) {
+ } catch (IOException ioe) {
baseFile = baseFile.getAbsoluteFile();
}
server.setCatalinaBase(baseFile);
@@ -829,7 +827,7 @@
}
try {
homeFile = homeFile.getCanonicalFile();
- } catch (IOException e) {
+ } catch (IOException ioe) {
homeFile = homeFile.getAbsoluteFile();
}
server.setCatalinaHome(homeFile);
@@ -877,10 +875,10 @@
/**
- * By default, when calling addWebapp() to create a Context, the settings from the default web.xml are added to
- * the context. Calling this method with a false value prior to calling addWebapp() allows to opt out
- * of the default settings. In that event you will need to add the configurations yourself, either programmatically
- * or by using web.xml deployment descriptors.
+ * By default, when calling addWebapp() to create a Context, the settings from the default web.xml are added to the
+ * context. Calling this method with a false value prior to calling addWebapp() allows to opt out of
+ * the default settings. In that event you will need to add the configurations yourself, either programmatically or
+ * by using web.xml deployment descriptors.
*
* @param addDefaultWebXmlToWebapp false will prevent the class from automatically adding the default
* settings when calling addWebapp(). true will add the default
@@ -993,7 +991,6 @@
*
MIME mappings (subset of those in conf/web.xml)
*
Welcome files
*
- * TODO: Align the MIME mappings with conf/web.xml - possibly via a common file.
*
* @param contextPath The path of the context to set the defaults for
*/
@@ -1035,11 +1032,15 @@
ctx.addWelcomeFile("index.html");
ctx.addWelcomeFile("index.htm");
ctx.addWelcomeFile("index.jsp");
+ // Any application configured welcome files should override the defaults.
+ if (ctx instanceof StandardContext) {
+ ((StandardContext) ctx).setReplaceWelcomeFiles(true);
+ }
}
/**
- * Add the default MIME type mappings to the provide Context.
+ * Add the default MIME type mappings to the provided Context.
*
* @param context The web application to which the default MIME type mappings should be added.
*/
@@ -1050,8 +1051,8 @@
for (Map.Entry