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

commit 326ff6da5595a4132e060b5c47d60c922f417355
Author: opencode <[email protected]>
AuthorDate: Thu Oct 15 11:33:42 2026 +0200

    Close the descriptor stream in the digester modeler source
    
    Registry.load() opens an input stream for URL and File sources and
    hands it to the modeler source without retaining any reference, so
    the stream had to be closed by the source that consumed it.
    MbeansDescriptorsDigesterSource.execute() previously cast the source
    to InputStream and parsed it without ever closing it, relying on the
    underlying SAX parser to release the stream. That left the release of
    the resource to unspecified parser behaviour.
    
    Validate the source with an instanceof check instead of a blind cast,
    throwing IllegalArgumentException for anything other than an
    InputStream, and parse inside a try-with-resources statement so the
    stream is closed when the parse completes, when it fails and when an
    unchecked error occurs.
    
    Add unit tests that pass a close-tracking input stream through
    Registry.load() and assert the stream is closed after both a
    successful parse and a parse error, and that a non-InputStream source
    is rejected with IllegalArgumentException.
---
 .../modules/MbeansDescriptorsDigesterSource.java   |  6 +-
 .../TestMbeansDescriptorsDigesterSource.java       | 90 ++++++++++++++++++++++
 2 files changed, 94 insertions(+), 2 deletions(-)

diff --git 
a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
 
b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
index 746a9fed53..9e271a7f2d 100644
--- 
a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
+++ 
b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java
@@ -142,7 +142,9 @@ public class MbeansDescriptorsDigesterSource extends 
ModelerSource {
             registry = Registry.getRegistry(null);
         }
 
-        InputStream stream = (InputStream) source;
+        if (!(source instanceof InputStream stream)) {
+            throw new 
IllegalArgumentException(sm.getString("registry.invalidSource"));
+        }
 
         List<ManagedBean> loadedMbeans = new ArrayList<>();
         synchronized (dLock) {
@@ -151,7 +153,7 @@ public class MbeansDescriptorsDigesterSource extends 
ModelerSource {
             }
 
             // Process the input file to configure our registry
-            try {
+            try (stream) {
                 // Push our registry object onto the stack
                 digester.push(loadedMbeans);
                 digester.parse(stream);
diff --git 
a/test/org/apache/tomcat/util/modeler/modules/TestMbeansDescriptorsDigesterSource.java
 
b/test/org/apache/tomcat/util/modeler/modules/TestMbeansDescriptorsDigesterSource.java
new file mode 100644
index 0000000000..c512cdf2fe
--- /dev/null
+++ 
b/test/org/apache/tomcat/util/modeler/modules/TestMbeansDescriptorsDigesterSource.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.modeler.modules;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.tomcat.util.modeler.Registry;
+
+public class TestMbeansDescriptorsDigesterSource {
+
+    private static final String XML =
+            "<?xml version=\"1.0\" 
encoding=\"UTF-8\"?>\n<mbeans-descriptors>\n" +
+                    "  <mbean name=\"TestDigesterSourceBean\" 
description=\"Tester bean\" domain=\"tester\">\n" +
+                    "    <attribute name=\"value\" description=\"Tester 
value\" type=\"java.lang.String\"/>\n" +
+                    "  </mbean>\n</mbeans-descriptors>\n";
+
+    private static final String BAD_XML = "<mbeans-descriptors><invalid>";
+
+    private static InputStream createTrackingStream(String content, 
AtomicBoolean closed) {
+        InputStream delegate = new 
ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+        return new FilterInputStream(delegate) {
+            @Override
+            public void close() throws IOException {
+                closed.set(true);
+                super.close();
+            }
+        };
+    }
+
+    @Test
+    public void testLoadClosesStreamAfterSuccessfulParse() throws Exception {
+        AtomicBoolean closed = new AtomicBoolean();
+        Registry registry = Registry.getRegistry(null);
+
+        registry.load(null, createTrackingStream(XML, closed), null);
+
+        Assert.assertTrue(closed.get());
+        
Assert.assertNotNull(registry.findManagedBean("TestDigesterSourceBean"));
+    }
+
+    @Test
+    public void testLoadClosesStreamAfterParseError() throws Exception {
+        AtomicBoolean closed = new AtomicBoolean();
+        Registry registry = Registry.getRegistry(null);
+
+        try {
+            registry.load(null, createTrackingStream(BAD_XML, closed), null);
+            Assert.fail("Expected a parse error");
+        } catch (Exception e) {
+            // Expected
+        }
+
+        Assert.assertTrue(closed.get());
+    }
+
+    @Test
+    public void testExecuteRequiresInputStreamSource() throws Exception {
+        Registry registry = Registry.getRegistry(null);
+        ModelerSource source = new MbeansDescriptorsDigesterSource();
+
+        try {
+            source.loadDescriptors(registry, "tester", "not-an-input-stream");
+            Assert.fail("Expected an IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to