This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 5c1a153feb09ed361a67af94cf7200a1f81e79d4 Author: remm <[email protected]> AuthorDate: Thu May 28 16:13:52 2026 +0200 Fix various issues Of note an unintended double connection in proxy error report valve. --- .../valves/CrawlerSessionManagerValve.java | 4 +- .../catalina/valves/JsonErrorReportValve.java | 4 +- .../apache/catalina/valves/LocalStrings.properties | 1 + .../apache/catalina/valves/PersistentValve.java | 6 +- .../catalina/valves/ProxyErrorReportValve.java | 2 +- java/org/apache/catalina/valves/SSLValve.java | 6 +- .../catalina/valves/rewrite/ResolverImpl.java | 151 +++++++++++---------- .../org/apache/coyote/ajp/AbstractAjpProtocol.java | 2 +- webapps/docs/changelog.xml | 3 + 9 files changed, 97 insertions(+), 82 deletions(-) diff --git a/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java b/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java index 3dcaefa071..58ff046a1b 100644 --- a/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java +++ b/java/org/apache/catalina/valves/CrawlerSessionManagerValve.java @@ -207,7 +207,7 @@ public class CrawlerSessionManagerValve extends ValveBase { protected void initInternal() throws LifecycleException { super.initInternal(); - uaPattern = Pattern.compile(crawlerUserAgents); + setCrawlerUserAgents(crawlerUserAgents); } @@ -248,7 +248,7 @@ public class CrawlerSessionManagerValve extends ValveBase { log.trace(request.hashCode() + ": UserAgent=" + uaHeader); } - if (uaPattern.matcher(uaHeader).matches()) { + if (uaPattern != null && uaPattern.matcher(uaHeader).matches()) { isBot = true; if (log.isTraceEnabled()) { diff --git a/java/org/apache/catalina/valves/JsonErrorReportValve.java b/java/org/apache/catalina/valves/JsonErrorReportValve.java index af6e4f1eec..a5b0a58747 100644 --- a/java/org/apache/catalina/valves/JsonErrorReportValve.java +++ b/java/org/apache/catalina/valves/JsonErrorReportValve.java @@ -95,6 +95,7 @@ public class JsonErrorReportValve extends ErrorReportValve { // Stack trace sb.append(" \"throwable\": ["); + int loops = 0; boolean first = true; do { if (!first) { @@ -121,7 +122,8 @@ public class JsonErrorReportValve extends ErrorReportValve { } throwable = throwable.getCause(); - } while (throwable != null); + loops++; + } while (throwable != null && (loops < 10)); sb.append("]\n}"); } else { diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties index 86b82d7449..908cb6f3ab 100644 --- a/java/org/apache/catalina/valves/LocalStrings.properties +++ b/java/org/apache/catalina/valves/LocalStrings.properties @@ -167,6 +167,7 @@ requestFilterValve.configInvalid=One or more invalid configuration settings were requestFilterValve.deny=Denied request for [{0}] based on property [{1}] sslValve.certError=Failed to process certificate string [{0}] to create a java.security.cert.X509Certificate object +sslValve.invalidHeader=Invalid value [{0}] for header [{1}] sslValve.invalidProvider=The SSL provider specified on the connector associated with this request of [{0}] is invalid. The certificate data could not be processed. stuckThreadDetectionValve.interrupted=Thread interrupted after the request is finished, ignoring diff --git a/java/org/apache/catalina/valves/PersistentValve.java b/java/org/apache/catalina/valves/PersistentValve.java index cd5ff5f8f8..5f67c89ebe 100644 --- a/java/org/apache/catalina/valves/PersistentValve.java +++ b/java/org/apache/catalina/valves/PersistentValve.java @@ -38,6 +38,8 @@ import org.apache.catalina.Store; import org.apache.catalina.StoreManager; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; /** * Valve that implements per-request session persistence. It is intended to be used with non-sticky load-balancers and a @@ -68,6 +70,8 @@ import org.apache.catalina.connector.Response; */ public class PersistentValve extends ValveBase { + private static final Log log = LogFactory.getLog(PersistentValve.class); + // Saves a couple of calls to getClassLoader() on every request. Under high // load these calls took just long enough to appear as a hot spot (although // a very minor one) in a profiler. @@ -348,7 +352,7 @@ public class PersistentValve extends ValveBase { try { this.filter = Pattern.compile(filter); } catch (PatternSyntaxException pse) { - container.getLogger().error(sm.getString("persistentValve.filter.failure", filter), pse); + log.error(sm.getString("persistentValve.filter.failure", filter), pse); } } } diff --git a/java/org/apache/catalina/valves/ProxyErrorReportValve.java b/java/org/apache/catalina/valves/ProxyErrorReportValve.java index bcacd9b021..d5788a1d29 100644 --- a/java/org/apache/catalina/valves/ProxyErrorReportValve.java +++ b/java/org/apache/catalina/valves/ProxyErrorReportValve.java @@ -239,7 +239,7 @@ public class ProxyErrorReportValve extends ErrorReportValve { response.setContentType(httpURLConnection.getContentType()); response.setContentLength(httpURLConnection.getContentLength()); OutputStream outputStream = response.getOutputStream(); - InputStream inputStream = url.openStream(); + InputStream inputStream = httpURLConnection.getInputStream(); IOTools.flow(inputStream, outputStream); } catch (URISyntaxException | IOException | IllegalArgumentException e) { if (log.isDebugEnabled()) { diff --git a/java/org/apache/catalina/valves/SSLValve.java b/java/org/apache/catalina/valves/SSLValve.java index 629563f58b..ca3b14d546 100644 --- a/java/org/apache/catalina/valves/SSLValve.java +++ b/java/org/apache/catalina/valves/SSLValve.java @@ -248,7 +248,11 @@ public class SSLValve extends ValveBase { } headerValue = mygetHeader(request, sslCipherUserKeySizeHeader); if (headerValue != null) { - request.setAttribute(Globals.KEY_SIZE_ATTR, Integer.valueOf(headerValue)); + try { + request.setAttribute(Globals.KEY_SIZE_ATTR, Integer.valueOf(headerValue)); + } catch (NumberFormatException e) { + log.warn(sm.getString("sslValve.invalidHeader", headerValue, sslCipherUserKeySizeHeader)); + } } getNext().invoke(request, response); } diff --git a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java index 512ada8569..6d8ff2ddea 100644 --- a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java +++ b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java @@ -187,87 +187,88 @@ public class ResolverImpl extends Resolver { @Override public String resolveSsl(String key) { - SSLSupport sslSupport = (SSLSupport) request.getAttribute(SSLSupport.SESSION_MGR); - try { - // SSL_SRP_USER: no planned support for SRP - // SSL_SRP_USERINFO: no planned support for SRP - if (key.equals("HTTPS")) { - return String.valueOf(sslSupport != null); - } else if (key.equals("SSL_PROTOCOL")) { - return sslSupport.getProtocol(); - } else if (key.equals("SSL_SESSION_ID")) { - return sslSupport.getSessionId(); - } else if (key.equals("SSL_SESSION_RESUMED")) { - // FIXME session resumption state, not available anywhere - } else if (key.equals("SSL_SECURE_RENEG")) { - // FIXME available from SSLHostConfig - } else if (key.equals("SSL_COMPRESS_METHOD")) { - // FIXME available from SSLHostConfig - } else if (key.equals("SSL_TLS_SNI")) { - // FIXME from handshake SNI processing - } else if (key.equals("SSL_CIPHER")) { - return sslSupport.getCipherSuite(); - } else if (key.equals("SSL_CIPHER_EXPORT")) { - String cipherSuite = sslSupport.getCipherSuite(); - if (cipherSuite != null) { - Set<Cipher> cipherList = OpenSSLCipherConfigurationParser.parse(cipherSuite); - if (cipherList.size() == 1) { - Cipher cipher = cipherList.iterator().next(); - if (cipher.getLevel().equals(EncryptionLevel.EXP40) || - cipher.getLevel().equals(EncryptionLevel.EXP56)) { - return "true"; - } else { - return "false"; + if (request.getAttribute(SSLSupport.SESSION_MGR) instanceof SSLSupport sslSupport) { + try { + // SSL_SRP_USER: no planned support for SRP + // SSL_SRP_USERINFO: no planned support for SRP + if (key.equals("HTTPS")) { + return String.valueOf(sslSupport != null); + } else if (key.equals("SSL_PROTOCOL")) { + return sslSupport.getProtocol(); + } else if (key.equals("SSL_SESSION_ID")) { + return sslSupport.getSessionId(); + } else if (key.equals("SSL_SESSION_RESUMED")) { + // FIXME session resumption state, not available anywhere + } else if (key.equals("SSL_SECURE_RENEG")) { + // FIXME available from SSLHostConfig + } else if (key.equals("SSL_COMPRESS_METHOD")) { + // FIXME available from SSLHostConfig + } else if (key.equals("SSL_TLS_SNI")) { + // FIXME from handshake SNI processing + } else if (key.equals("SSL_CIPHER")) { + return sslSupport.getCipherSuite(); + } else if (key.equals("SSL_CIPHER_EXPORT")) { + String cipherSuite = sslSupport.getCipherSuite(); + if (cipherSuite != null) { + Set<Cipher> cipherList = OpenSSLCipherConfigurationParser.parse(cipherSuite); + if (cipherList.size() == 1) { + Cipher cipher = cipherList.iterator().next(); + if (cipher.getLevel().equals(EncryptionLevel.EXP40) || + cipher.getLevel().equals(EncryptionLevel.EXP56)) { + return "true"; + } else { + return "false"; + } } } - } - } else if (key.equals("SSL_CIPHER_ALGKEYSIZE")) { - String cipherSuite = sslSupport.getCipherSuite(); - if (cipherSuite != null) { - Set<Cipher> cipherList = OpenSSLCipherConfigurationParser.parse(cipherSuite); - if (cipherList.size() == 1) { - Cipher cipher = cipherList.iterator().next(); - return String.valueOf(cipher.getAlg_bits()); + } else if (key.equals("SSL_CIPHER_ALGKEYSIZE")) { + String cipherSuite = sslSupport.getCipherSuite(); + if (cipherSuite != null) { + Set<Cipher> cipherList = OpenSSLCipherConfigurationParser.parse(cipherSuite); + if (cipherList.size() == 1) { + Cipher cipher = cipherList.iterator().next(); + return String.valueOf(cipher.getAlg_bits()); + } } - } - } else if (key.equals("SSL_CIPHER_USEKEYSIZE")) { - Integer keySize = sslSupport.getKeySize(); - return (keySize == null) ? null : sslSupport.getKeySize().toString(); - } else if (key.startsWith("SSL_CLIENT_")) { - X509Certificate[] certificates = sslSupport.getPeerCertificateChain(); - if (certificates != null && certificates.length > 0) { - key = key.substring("SSL_CLIENT_".length()); - String result = resolveSslCertificates(key, certificates); - if (result != null) { - return result; - } else if (key.startsWith("SAN_OTHER_msUPN_")) { - // Type otherName, which is 0 - key = key.substring("SAN_OTHER_msUPN_".length()); - // FIXME OID from resolveAlternateName - } else if (key.equals("CERT_RFC4523_CEA")) { - // FIXME return certificate[0] format CertificateExactAssertion in RFC4523 - } else if (key.equals("VERIFY")) { - // FIXME return verification state, not available anywhere + } else if (key.equals("SSL_CIPHER_USEKEYSIZE")) { + Integer keySize = sslSupport.getKeySize(); + return (keySize == null) ? null : sslSupport.getKeySize().toString(); + } else if (key.startsWith("SSL_CLIENT_")) { + X509Certificate[] certificates = sslSupport.getPeerCertificateChain(); + if (certificates != null && certificates.length > 0) { + key = key.substring("SSL_CLIENT_".length()); + String result = resolveSslCertificates(key, certificates); + if (result != null) { + return result; + } else if (key.startsWith("SAN_OTHER_msUPN_")) { + // Type otherName, which is 0 + key = key.substring("SAN_OTHER_msUPN_".length()); + // FIXME OID from resolveAlternateName + } else if (key.equals("CERT_RFC4523_CEA")) { + // FIXME return certificate[0] format CertificateExactAssertion in RFC4523 + } else if (key.equals("VERIFY")) { + // FIXME return verification state, not available anywhere + } } - } - } else if (key.startsWith("SSL_SERVER_")) { - X509Certificate[] certificates = sslSupport.getLocalCertificateChain(); - if (certificates != null && certificates.length > 0) { - key = key.substring("SSL_SERVER_".length()); - String result = resolveSslCertificates(key, certificates); - if (result != null) { - return result; - } else if (key.startsWith("SAN_OTHER_dnsSRV_")) { - // Type otherName, which is 0 - key = key.substring("SAN_OTHER_dnsSRV_".length()); - // FIXME OID from resolveAlternateName + } else if (key.startsWith("SSL_SERVER_")) { + X509Certificate[] certificates = sslSupport.getLocalCertificateChain(); + if (certificates != null && certificates.length > 0) { + key = key.substring("SSL_SERVER_".length()); + String result = resolveSslCertificates(key, certificates); + if (result != null) { + return result; + } else if (key.startsWith("SAN_OTHER_dnsSRV_")) { + // Type otherName, which is 0 + key = key.substring("SAN_OTHER_dnsSRV_".length()); + // FIXME OID from resolveAlternateName + } } } - } - } catch (IOException ioe) { - // TLS access error - if (containerLog.isDebugEnabled()) { - containerLog.debug(sm.getString("resolverImpl.tlsError"), ioe); + } catch (IOException ioe) { + // TLS access error + if (containerLog.isDebugEnabled()) { + containerLog.debug(sm.getString("resolverImpl.tlsError"), ioe); + } } } return null; diff --git a/java/org/apache/coyote/ajp/AbstractAjpProtocol.java b/java/org/apache/coyote/ajp/AbstractAjpProtocol.java index 337b0ce872..c930c4ccd9 100644 --- a/java/org/apache/coyote/ajp/AbstractAjpProtocol.java +++ b/java/org/apache/coyote/ajp/AbstractAjpProtocol.java @@ -245,7 +245,7 @@ public abstract class AbstractAjpProtocol<S> extends AbstractProtocol<S> { * @return the pattern string */ public String getAllowedRequestAttributesPattern() { - return allowedRequestAttributesPattern.pattern(); + return allowedRequestAttributesPattern != null ? allowedRequestAttributesPattern.pattern() : null; } /** diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 522202efc5..f366d503dc 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -207,6 +207,9 @@ than a <code>500</code> response. Pull request <pr>1012</pr> provided by Sahana Surendra Bogar. (markt) </fix> + <fix> + Fix connection leak in <code>ProxyErrorReportValve</code>. (remm) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
