This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push:
new 4d20e86db3 Minor fixes from code review
4d20e86db3 is described below
commit 4d20e86db36bbab6148a4704a69914eaaa9fae64
Author: remm <[email protected]>
AuthorDate: Wed Jun 10 16:42:47 2026 +0200
Minor fixes from code review
---
.../catalina/ant/jmx/JMXAccessorConditionBase.java | 3 +-
.../catalina/ant/jmx/JMXAccessorCreateTask.java | 6 ++-
.../ant/jmx/JMXAccessorEqualsCondition.java | 1 -
.../catalina/ant/jmx/JMXAccessorGetTask.java | 4 +-
.../catalina/ant/jmx/JMXAccessorInvokeTask.java | 3 ++
.../catalina/ant/jmx/JMXAccessorQueryTask.java | 5 +-
.../catalina/ant/jmx/JMXAccessorSetTask.java | 4 +-
.../apache/catalina/ant/jmx/JMXAccessorTask.java | 25 +++++----
.../ant/jmx/JMXAccessorUnregisterTask.java | 8 +--
.../catalina/authenticator/BasicAuthenticator.java | 6 ++-
.../apache/catalina/authenticator/Constants.java | 12 ++---
.../authenticator/DigestAuthenticator.java | 3 +-
.../catalina/authenticator/SingleSignOnEntry.java | 3 +-
.../authenticator/SpnegoAuthenticator.java | 2 +-
.../jaspic/PersistentProviderRegistrations.java | 7 +--
.../jaspic/SimpleServerAuthContext.java | 8 ++-
.../apache/catalina/connector/CoyotePrincipal.java | 20 +++++++
.../apache/catalina/connector/CoyoteReader.java | 3 ++
.../apache/catalina/connector/CoyoteWriter.java | 1 -
java/org/apache/catalina/connector/Request.java | 5 +-
java/org/apache/catalina/connector/Response.java | 17 ++++--
.../apache/catalina/connector/ResponseFacade.java | 8 +--
.../org/apache/catalina/core/AccessLogAdapter.java | 8 ++-
.../apache/catalina/realm/GenericPrincipal.java | 19 +++++++
.../buildutil/translate/BackportTranslations.java | 5 +-
.../apache/tomcat/buildutil/translate/Import.java | 1 +
threadpool.patch | 63 ++++++++++++++++++++++
27 files changed, 195 insertions(+), 55 deletions(-)
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
index e114f25439..7f64bbc81b 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorConditionBase.java
@@ -22,6 +22,7 @@ import java.net.MalformedURLException;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
+import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.taskdefs.condition.Condition;
@@ -233,7 +234,7 @@ public abstract class JMXAccessorConditionBase extends
ProjectComponent implemen
return result.toString();
}
} catch (Exception e) {
- // ignore access or connection open errors
+ throw new BuildException("Cannot access JMX value for condition",
e);
}
return null;
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
index be1fa8ee2f..18bc588615 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
@@ -139,12 +139,14 @@ public class JMXAccessorCreateTask extends
JMXAccessorTask {
@Override
public String jmxExecute(MBeanServerConnection jmxServerConnection) throws
Exception {
-
if (getName() == null) {
throw new BuildException("Must specify a 'name'");
}
if ((className == null)) {
- throw new BuildException("Must specify a 'className' for get");
+ throw new BuildException("Must specify a 'className' for create");
+ }
+ if (jmxServerConnection == null) {
+ throw new BuildException("Must open a connection!");
}
jmxCreate(jmxServerConnection, getName());
return null;
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
index a58fef60b4..b8d2c87ecc 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
@@ -74,7 +74,6 @@ public class JMXAccessorEqualsCondition extends
JMXAccessorConditionBase {
if (getName() == null || getAttribute() == null) {
throw new BuildException("Must specify an MBean name and attribute
for equals condition");
}
- // FIXME check url or host/parameter
String jmxValue = accessJMXValue();
if (jmxValue != null) {
return jmxValue.equals(value);
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
index 4ad5b6c011..78fe5dfece 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
@@ -89,13 +89,15 @@ public class JMXAccessorGetTask extends JMXAccessorTask {
@Override
public String jmxExecute(MBeanServerConnection jmxServerConnection) throws
Exception {
-
if (getName() == null) {
throw new BuildException("Must specify a 'name'");
}
if ((attribute == null)) {
throw new BuildException("Must specify a 'attribute' for get");
}
+ if (jmxServerConnection == null) {
+ throw new BuildException("Must open a connection!");
+ }
return jmxGet(jmxServerConnection, getName());
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
index 7fa478cb35..f1d0c50eb7 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
@@ -156,6 +156,9 @@ public class JMXAccessorInvokeTask extends JMXAccessorTask {
if ((operation == null)) {
throw new BuildException("Must specify a 'operation' for call");
}
+ if (jmxServerConnection == null) {
+ throw new BuildException("Must open a connection!");
+ }
return jmxInvoke(jmxServerConnection, getName());
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
index 600f17751a..7e70bb7287 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
@@ -90,12 +90,13 @@ public class JMXAccessorQueryTask extends JMXAccessorTask {
@Override
public String jmxExecute(MBeanServerConnection jmxServerConnection) throws
Exception {
-
if (getName() == null) {
throw new BuildException("Must specify a 'name'");
}
+ if (jmxServerConnection == null) {
+ throw new BuildException("Must open a connection!");
+ }
return jmxQuery(jmxServerConnection, getName());
-
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
index 08fae8da40..b09de55dd7 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
@@ -151,13 +151,15 @@ public class JMXAccessorSetTask extends JMXAccessorTask {
@Override
public String jmxExecute(MBeanServerConnection jmxServerConnection) throws
Exception {
-
if (getName() == null) {
throw new BuildException("Must specify a 'name'");
}
if ((attribute == null || value == null)) {
throw new BuildException("Must specify a 'attribute' and 'value'
for set");
}
+ if (jmxServerConnection == null) {
+ throw new BuildException("Must open a connection!");
+ }
return jmxSet(jmxServerConnection, getName());
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
index 8e27366a44..d9d2d1cd67 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java
@@ -22,7 +22,6 @@ import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -436,6 +435,7 @@ public class JMXAccessorTask extends
BaseRedirectorHelperTask {
environment = new HashMap<>();
environment.put(JMXConnector.CREDENTIALS, credentials);
}
+ // FIXME: Referencing JMXConnector instead of MBeanServerConnection is
needed to close the connection
return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX),
environment).getMBeanServerConnection();
}
@@ -515,7 +515,6 @@ public class JMXAccessorTask extends
BaseRedirectorHelperTask {
* @return the JMX connection
*/
protected MBeanServerConnection getJMXConnection() throws
MalformedURLException, IOException {
-
MBeanServerConnection jmxServerConnection = null;
if (isUseRef()) {
Object pref;
@@ -552,8 +551,7 @@ public class JMXAccessorTask extends
BaseRedirectorHelperTask {
* @exception Exception if an error occurs
*/
public String jmxExecute(MBeanServerConnection jmxServerConnection) throws
Exception {
-
- if ((jmxServerConnection == null)) {
+ if (jmxServerConnection == null) {
throw new BuildException("Must open a connection!");
} else if (isEcho()) {
handleOutput("JMX Connection ref=" + ref + " is open!");
@@ -562,7 +560,7 @@ public class JMXAccessorTask extends
BaseRedirectorHelperTask {
}
/**
- * Convert string to datatype FIXME How we can transfer values from ant
project reference store (ref)?
+ * Convert string to datatype.
*
* @param value The value
* @param valueType The type
@@ -686,15 +684,16 @@ public class JMXAccessorTask extends
BaseRedirectorHelperTask {
}
}
} else if (result instanceof TabularDataSupport data) {
- for (Object key : data.keySet()) {
- for (Object key1 : ((List<?>) key)) {
- CompositeData valuedata = data.get(new Object[] { key1 });
- Object value = valuedata.get("value");
- OpenType<?> type =
valuedata.getCompositeType().getType("value");
- if (type instanceof SimpleType<?>) {
- setProperty(propertyPrefix + "." + key1, value);
+ for (Object rowObj : data.values()) {
+ CompositeData row = (CompositeData) rowObj;
+ CompositeType rowType = row.getCompositeType();
+ for (String fieldName : rowType.keySet()) {
+ Object fieldValue = row.get(fieldName);
+ OpenType<?> fieldType = rowType.getType(fieldName);
+ if (fieldType instanceof SimpleType<?>) {
+ setProperty(propertyPrefix + "." + fieldName,
fieldValue);
} else {
- createProperty(propertyPrefix + "." + key1, value);
+ createProperty(propertyPrefix + "." + fieldName,
fieldValue);
}
}
}
diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
b/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
index ed09b0fb09..ad7e47ac00 100644
--- a/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
+++ b/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
@@ -59,11 +59,13 @@ public class JMXAccessorUnregisterTask extends
JMXAccessorTask {
@Override
public String jmxExecute(MBeanServerConnection jmxServerConnection) throws
Exception {
-
if (getName() == null) {
throw new BuildException("Must specify a 'name'");
}
- return jmxUuregister(jmxServerConnection, getName());
+ if (jmxServerConnection == null) {
+ throw new BuildException("Must open a connection!");
+ }
+ return jmxUnregister(jmxServerConnection, getName());
}
@@ -77,7 +79,7 @@ public class JMXAccessorUnregisterTask extends
JMXAccessorTask {
*
* @throws Exception An error occurred
*/
- protected String jmxUuregister(MBeanServerConnection jmxServerConnection,
String name) throws Exception {
+ protected String jmxUnregister(MBeanServerConnection jmxServerConnection,
String name) throws Exception {
if (isEcho()) {
handleOutput("Unregister MBean " + name);
}
diff --git a/java/org/apache/catalina/authenticator/BasicAuthenticator.java
b/java/org/apache/catalina/authenticator/BasicAuthenticator.java
index 27f511ea30..68f915bb21 100644
--- a/java/org/apache/catalina/authenticator/BasicAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/BasicAuthenticator.java
@@ -50,7 +50,8 @@ public class BasicAuthenticator extends AuthenticatorBase {
/**
- * Returns the character set used for encoding credentials.
+ * Returns the character set used for encoding credentials, as set by the
user.
+ * If the charset was null or empty, the effective charset will be
ISO-8859-1.
*
* @return the character set name
*/
@@ -60,7 +61,8 @@ public class BasicAuthenticator extends AuthenticatorBase {
/**
- * Sets the character set used for encoding credentials.
+ * Sets the character set used for encoding credentials. Empty charsets
will set
+ * ISO-8859-1.
*
* @param charsetString the character set name
*/
diff --git a/java/org/apache/catalina/authenticator/Constants.java
b/java/org/apache/catalina/authenticator/Constants.java
index ecc11979c0..336baaa099 100644
--- a/java/org/apache/catalina/authenticator/Constants.java
+++ b/java/org/apache/catalina/authenticator/Constants.java
@@ -115,16 +115,16 @@ public class Constants {
/**
- * If the <code>cache</code> property of the authenticator is set, and the
current request is part of a session, the
- * password used to authenticate this user will be cached under this key
to avoid the need for repeated calls to
- * <code>Realm.authenticate()</code>.
+ * When the <code>cache</code> property of the authenticator is set to
<code>false</code>, the Principal is not cached.
+ * In this case, if the current request is part of a session, the password
used to authenticate this user will be stored
+ * under this key so the user can be re-authenticated on subsequent
requests.
*/
public static final String SESS_PASSWORD_NOTE =
"org.apache.catalina.session.PASSWORD";
/**
- * If the <code>cache</code> property of the authenticator is set, and the
current request is part of a session, the
- * username used to authenticate this user will be cached under this key
to avoid the need for repeated calls to
- * <code>Realm.authenticate()</code>.
+ * When the <code>cache</code> property of the authenticator is set to
<code>false</code>, the Principal is not cached.
+ * In this case, if the current request is part of a session, the username
used to authenticate this user will be stored
+ * under this key so the user can be re-authenticated on subsequent
requests.
*/
public static final String SESS_USERNAME_NOTE =
"org.apache.catalina.session.USERNAME";
diff --git a/java/org/apache/catalina/authenticator/DigestAuthenticator.java
b/java/org/apache/catalina/authenticator/DigestAuthenticator.java
index a6c2cd9205..1189156b97 100644
--- a/java/org/apache/catalina/authenticator/DigestAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/DigestAuthenticator.java
@@ -665,8 +665,7 @@ public class DigestAuthenticator extends AuthenticatorBase {
}
// Validate the Realm name
- String lcRealm = getRealmName(request.getContext());
- if (!lcRealm.equals(realmName)) {
+ if (!realmName.equals(getRealmName(request.getContext()))) {
return false;
}
diff --git a/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
b/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
index ca82255023..5d233ac253 100644
--- a/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
+++ b/java/org/apache/catalina/authenticator/SingleSignOnEntry.java
@@ -59,7 +59,8 @@ public class SingleSignOnEntry implements Serializable {
private transient Principal principal = null;
/**
- * Map of session keys associated with this SSO entry.
+ * Set of session keys associated with this SSO entry. Backed by
ConcurrentHashMap to take
+ * advantage of its thread safety features.
*/
private final Map<SingleSignOnSessionKey,SingleSignOnSessionKey>
sessionKeys = new ConcurrentHashMap<>();
diff --git a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
index f7dd01a851..4a5a2236ba 100644
--- a/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
+++ b/java/org/apache/catalina/authenticator/SpnegoAuthenticator.java
@@ -327,7 +327,7 @@ public class SpnegoAuthenticator extends AuthenticatorBase {
}
}
- // Send response token on success and failure
+ // Send response token since one is available, even for SC_UNAUTHORIZED
response.setHeader(AUTH_HEADER_NAME,
AUTH_HEADER_VALUE_NEGOTIATE + " " +
Base64.getEncoder().encodeToString(outToken));
diff --git
a/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
b/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
index 0f5ba37615..98b510f608 100644
---
a/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
+++
b/java/org/apache/catalina/authenticator/jaspic/PersistentProviderRegistrations.java
@@ -37,6 +37,7 @@ import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.security.Escape;
import org.xml.sax.SAXException;
/**
@@ -136,9 +137,9 @@ public final class PersistentProviderRegistrations {
writer.write(">\n");
for (Entry<String,String> entry :
provider.getProperties().entrySet()) {
writer.write(" <property name=\"");
- writer.write(entry.getKey());
+ writer.write(Escape.xml(entry.getKey()));
writer.write("\" value=\"");
- writer.write(entry.getValue());
+ writer.write(Escape.xml(entry.getValue()));
writer.write("\"/>\n");
}
writer.write(" </provider>\n");
@@ -177,7 +178,7 @@ public final class PersistentProviderRegistrations {
private static void writeOptional(String name, String value, Writer
writer) throws IOException {
if (value != null) {
writer.write(" " + name + "=\"");
- writer.write(value);
+ writer.write(Escape.xml(value));
writer.write("\"");
}
}
diff --git
a/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthContext.java
b/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthContext.java
index 5aaaf27786..c87ec2950c 100644
--- a/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthContext.java
+++ b/java/org/apache/catalina/authenticator/jaspic/SimpleServerAuthContext.java
@@ -73,8 +73,12 @@ public class SimpleServerAuthContext implements
ServerAuthContext {
*/
@Override
public AuthStatus secureResponse(MessageInfo messageInfo, Subject
serviceSubject) throws AuthException {
- ServerAuthModule module = modules.get(((Integer)
messageInfo.getMap().get("moduleIndex")).intValue());
- return module.secureResponse(messageInfo, serviceSubject);
+ if (messageInfo.getMap().get("moduleIndex") instanceof Integer
moduleIndex) {
+ ServerAuthModule module = modules.get(moduleIndex.intValue());
+ return module.secureResponse(messageInfo, serviceSubject);
+ } else {
+ return AuthStatus.SEND_FAILURE;
+ }
}
diff --git a/java/org/apache/catalina/connector/CoyotePrincipal.java
b/java/org/apache/catalina/connector/CoyotePrincipal.java
index 32257536d6..35621823e2 100644
--- a/java/org/apache/catalina/connector/CoyotePrincipal.java
+++ b/java/org/apache/catalina/connector/CoyotePrincipal.java
@@ -19,6 +19,7 @@ package org.apache.catalina.connector;
import java.io.Serial;
import java.io.Serializable;
import java.security.Principal;
+import java.util.Objects;
/**
* Generic implementation of <strong>java.security.Principal</strong> that is
used to represent principals authenticated
@@ -70,4 +71,23 @@ public class CoyotePrincipal implements Principal,
Serializable {
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ CoyotePrincipal that = (CoyotePrincipal) obj;
+ return Objects.equals(this.name, that.name);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ }
+
+
}
diff --git a/java/org/apache/catalina/connector/CoyoteReader.java
b/java/org/apache/catalina/connector/CoyoteReader.java
index 1b23f33083..2620226b20 100644
--- a/java/org/apache/catalina/connector/CoyoteReader.java
+++ b/java/org/apache/catalina/connector/CoyoteReader.java
@@ -57,6 +57,9 @@ public class CoyoteReader extends BufferedReader {
* @param ib The underlying input buffer
*/
public CoyoteReader(InputBuffer ib) {
+ // BufferedReader requires a non-zero buffer size. All read operations
are
+ // overridden to delegate directly to InputBuffer, so the parent
buffer is
+ // never used. Size of 1 minimizes the allocation.
super(ib, 1);
this.ib = ib;
}
diff --git a/java/org/apache/catalina/connector/CoyoteWriter.java
b/java/org/apache/catalina/connector/CoyoteWriter.java
index 5f036d429a..0cfc488aa8 100644
--- a/java/org/apache/catalina/connector/CoyoteWriter.java
+++ b/java/org/apache/catalina/connector/CoyoteWriter.java
@@ -118,7 +118,6 @@ public class CoyoteWriter extends PrintWriter {
} catch (IOException ignore) {
// Ignore
}
- error = false;
}
diff --git a/java/org/apache/catalina/connector/Request.java
b/java/org/apache/catalina/connector/Request.java
index ae19b2e1d6..2ab88e0da9 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -1496,6 +1496,9 @@ public class Request implements HttpServletRequest {
*/
private void notifyAttributeRemoved(String name, Object value) {
Context context = getContext();
+ if (context == null) {
+ return;
+ }
Object[] listeners = context.getApplicationEventListeners();
if (listeners == null || listeners.length == 0) {
return;
@@ -3037,7 +3040,7 @@ public class Request implements HttpServletRequest {
int len = 0;
while (len > -1) {
len = getStream().read(buffer, 0, CACHED_POST_LEN);
- if (connector.getMaxPostSize() >= 0 && (body.getLength() + len) >
connector.getMaxPostSize()) {
+ if (connector.getMaxPostSize() >= 0 && ((long) body.getLength() +
len) > connector.getMaxPostSize()) {
// Too much data
checkSwallowInput();
throw new
InvalidParameterException(sm.getString("coyoteRequest.chunkedPostTooLarge"),
diff --git a/java/org/apache/catalina/connector/Response.java
b/java/org/apache/catalina/connector/Response.java
index 0d497d0c78..6b9229c64b 100644
--- a/java/org/apache/catalina/connector/Response.java
+++ b/java/org/apache/catalina/connector/Response.java
@@ -901,6 +901,9 @@ public class Response implements HttpServletResponse {
}
String header = generateCookieString(cookie);
+ if (header == null) {
+ return;
+ }
// if we reached here, no exception, cookie is valid
addHeader("Set-Cookie", header,
getContext().getCookieProcessor().getCharset());
}
@@ -919,6 +922,9 @@ public class Response implements HttpServletResponse {
final String headername = "Set-Cookie";
final String startsWith = name + "=";
String header = generateCookieString(cookie);
+ if (header == null) {
+ return;
+ }
boolean set = false;
MimeHeaders headers = getCoyoteResponse().getMimeHeaders();
int n = headers.size();
@@ -944,9 +950,14 @@ public class Response implements HttpServletResponse {
* @return The cookie header string
*/
public String generateCookieString(final Cookie cookie) {
- // Web application code can receive a IllegalArgumentException
- // from the generateHeader() invocation
- return getContext().getCookieProcessor().generateHeader(cookie,
request.getRequest());
+ Context context = getContext();
+ if (context != null) {
+ // Web application code can receive a IllegalArgumentException
+ // from the generateHeader() invocation
+ return context.getCookieProcessor().generateHeader(cookie,
request.getRequest());
+ } else {
+ return null;
+ }
}
diff --git a/java/org/apache/catalina/connector/ResponseFacade.java
b/java/org/apache/catalina/connector/ResponseFacade.java
index fe607b3dd1..1ebf9d9489 100644
--- a/java/org/apache/catalina/connector/ResponseFacade.java
+++ b/java/org/apache/catalina/connector/ResponseFacade.java
@@ -122,18 +122,14 @@ public class ResponseFacade implements
HttpServletResponse {
@Override
public ServletOutputStream getOutputStream() throws IOException {
- if (isFinished()) {
- response.setSuspended(true);
- }
+ checkFacade();
return response.getOutputStream();
}
@Override
public PrintWriter getWriter() throws IOException {
- if (isFinished()) {
- response.setSuspended(true);
- }
+ checkFacade();
return response.getWriter();
}
diff --git a/java/org/apache/catalina/core/AccessLogAdapter.java
b/java/org/apache/catalina/core/AccessLogAdapter.java
index 64afeb513e..38a3f62aeb 100644
--- a/java/org/apache/catalina/core/AccessLogAdapter.java
+++ b/java/org/apache/catalina/core/AccessLogAdapter.java
@@ -66,8 +66,12 @@ public class AccessLogAdapter implements AccessLog {
@Override
public boolean getRequestAttributesEnabled() {
- // NOOP. Could return logs[0].getRequestAttributesEnabled(), but I do
- // not see a use case for that.
+ for (AccessLog log : logs) {
+ // Return true if any AccessLog is going to use the attributes
+ if (log.getRequestAttributesEnabled()) {
+ return true;
+ }
+ }
return false;
}
}
diff --git a/java/org/apache/catalina/realm/GenericPrincipal.java
b/java/org/apache/catalina/realm/GenericPrincipal.java
index 7a3ce603b4..ad39e36563 100644
--- a/java/org/apache/catalina/realm/GenericPrincipal.java
+++ b/java/org/apache/catalina/realm/GenericPrincipal.java
@@ -223,6 +223,25 @@ public class GenericPrincipal implements TomcatPrincipal,
Serializable {
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ GenericPrincipal that = (GenericPrincipal) obj;
+ return Objects.equals(this.name, that.name);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name);
+ }
+
+
@Override
public void logout() throws Exception {
if (loginContext != null) {
diff --git
a/java/org/apache/tomcat/buildutil/translate/BackportTranslations.java
b/java/org/apache/tomcat/buildutil/translate/BackportTranslations.java
index aaa65fd0c1..183a653372 100644
--- a/java/org/apache/tomcat/buildutil/translate/BackportTranslations.java
+++ b/java/org/apache/tomcat/buildutil/translate/BackportTranslations.java
@@ -58,6 +58,10 @@ public class BackportTranslations extends BackportBase {
}
Properties sourceTranslated = sourceTranslations.get(language);
+ if (sourceTranslated == null) {
+ sourceTranslated = new Properties();
+ sourceTranslations.put(language, sourceTranslated);
+ }
Properties targetTranslated = targetTranslations.get(language);
if (targetTranslated == null) {
targetTranslated = new Properties();
@@ -66,7 +70,6 @@ public class BackportTranslations extends BackportBase {
for (Object key : targetEnglish.keySet()) {
if (sourceTranslated.containsKey(key) &&
targetEnglish.get(key).equals(sourceEnglish.get(key))) {
-
targetTranslated.put(key, sourceTranslated.get(key));
}
}
diff --git a/java/org/apache/tomcat/buildutil/translate/Import.java
b/java/org/apache/tomcat/buildutil/translate/Import.java
index 4fce11cd59..0f562309a3 100644
--- a/java/org/apache/tomcat/buildutil/translate/Import.java
+++ b/java/org/apache/tomcat/buildutil/translate/Import.java
@@ -89,6 +89,7 @@ public class Import {
}
File outFile = new File(currentPkg.replace('.',
File.separatorChar),
Constants.L10N_PREFIX + language +
Constants.L10N_SUFFIX);
+ // fos will be closed through w if w is replaced by another one
FileOutputStream fos = new FileOutputStream(outFile);
w = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
org.apache.tomcat.buildutil.Utils.insertLicense(w);
diff --git a/threadpool.patch b/threadpool.patch
new file mode 100644
index 0000000000..97b3afcecc
--- /dev/null
+++ b/threadpool.patch
@@ -0,0 +1,63 @@
+diff --git
a/java/org/apache/tomcat/util/descriptor/web/SecurityConstraint.java
b/java/org/apache/tomcat/util/descriptor/web/SecurityConstraint.java
+index 0451582..785a352 100644
+--- a/java/org/apache/tomcat/util/descriptor/web/SecurityConstraint.java
++++ b/java/org/apache/tomcat/util/descriptor/web/SecurityConstraint.java
+@@ -610,7 +610,7 @@
+ }
+
+ if (create) {
+- collection.addPattern(urlPattern);
++ collection.addPatternDecoded(urlPattern);
+ constraint.addCollection(collection);
+ return constraint;
+ }
+diff --git a/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
b/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
+index 6c61572..3a6636f 100644
+--- a/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
++++ b/java/org/apache/tomcat/util/threads/ThreadPoolExecutor.java
+@@ -662,6 +662,11 @@
+ * ScheduledThreadPoolExecutor.
+ */
+ final void reject(Runnable command) {
++ // Decrement before calling the handler so non-throwing handlers
++ // (DiscardPolicy, CallerRunsPolicy, DiscardOldestPolicy) don't leak
++ // submittedCount. If the handler throws, the decrement is accounted
++ // for in the catch block of execute().
++ submittedCount.decrementAndGet();
+ handler.rejectedExecution(command, this);
+ }
+
+@@ -1102,11 +1107,13 @@
+ // TaskQueue) in some tasks being rejected rather than queued.
+ // If this happens, add them to the queue.
+ if (!queue.force(command)) {
+- submittedCount.decrementAndGet();
+ throw new
RejectedExecutionException(sm.getString("threadPoolExecutor.queueFull"));
+ }
++ // Task was force-queued and will run through a worker, so
++ // afterExecute() will decrement. Re-increment to cancel the
++ // decrement that was done in reject() before the handler
threw.
++ submittedCount.incrementAndGet();
+ } else {
+- submittedCount.decrementAndGet();
+ throw rx;
+ }
+ }
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index 24b0d72..4e92dd0 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -415,6 +415,12 @@
+ <code>isTrailerFieldsReady</code> was always returning
+ <code>true</code>. (remm)
+ </fix>
++ <fix>
++ Fix <code>submittedCount</code> leak with the thread pool when using
++ non default <code>RejectedExecutionHandler</code>. The default handler
++ is throwing an exception on rejection and was processed properly.
++ (remm)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="Jasper">
+
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]