This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 435ae3ae9be10a10ba05738badf1346a55408acf
Author: opencode <[email protected]>
AuthorDate: Wed Oct 7 11:31:59 2026 +0200

    Allow re-adding a host that was previously removed with manager.xml
    
    Removing a host does not physically remove the host configuration
    directory. When the removed host had been created with the manager
    attribute, the manager.xml copy installed in the configuration
    directory for that host remained behind. Adding a host again with the
    same name and manager=true then failed with "Couldn't install
    manager.xml" because Files.copy() refuses to replace an existing
    target, so the host was never created. This is a common flow since the
    HTML add form checks the manager option by default.
    
    Copy manager.xml with StandardCopyOption.REPLACE_EXISTING so the
    template shipped with the running host manager application overwrites
    the leftover file, matching the behaviour of a fresh add.
    
    Add a test covering add, remove and re-add with manager=true.
---
 .../catalina/manager/host/HostManagerServlet.java  |  6 +-
 .../catalina/manager/TestHostManagerWebapp.java    | 95 ++++++++++++++++++++++
 2 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/catalina/manager/host/HostManagerServlet.java 
b/java/org/apache/catalina/manager/host/HostManagerServlet.java
index 66fc50cfc4..45b105db0e 100644
--- a/java/org/apache/catalina/manager/host/HostManagerServlet.java
+++ b/java/org/apache/catalina/manager/host/HostManagerServlet.java
@@ -23,6 +23,7 @@ import java.io.PrintWriter;
 import java.lang.management.ManagementFactory;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import java.util.StringTokenizer;
 
 import javax.management.InstanceNotFoundException;
@@ -386,7 +387,10 @@ public class HostManagerServlet extends HttpServlet 
implements ContainerServlet
                     return;
                 }
                 Path dest = new File(configBaseFile, "manager.xml").toPath();
-                Files.copy(is, dest);
+                // Replace any manager.xml left behind by a previous host
+                // with the same name. Removing a host does not delete the
+                // configuration directory.
+                Files.copy(is, dest, StandardCopyOption.REPLACE_EXISTING);
             } catch (IOException ioe) {
                 
writer.println(smClient.getString("hostManagerServlet.managerXml"));
                 return;
diff --git a/test/org/apache/catalina/manager/TestHostManagerWebapp.java 
b/test/org/apache/catalina/manager/TestHostManagerWebapp.java
index e2af5fca9a..9330254a2d 100644
--- a/test/org/apache/catalina/manager/TestHostManagerWebapp.java
+++ b/test/org/apache/catalina/manager/TestHostManagerWebapp.java
@@ -297,4 +297,99 @@ public class TestHostManagerWebapp extends TomcatBaseTest {
 
         tomcat.stop();
     }
+
+
+    /*
+     * Removing a host leaves the configuration directory in place. Re-adding
+     * a host with the same name using manager=true must then replace the
+     * leftover manager.xml rather than failing to install it.
+     */
+    @Test
+    public void testAddRemoveReAddWithManager() throws Exception {
+        System.setProperty("catalina.home", 
getBuildDirectory().getAbsolutePath());
+        Tomcat tomcat = getTomcatInstance();
+        tomcat.setAddDefaultWebXmlToWebapp(false);
+
+        File configFile = new File(getTemporaryDirectory(), 
"tomcat-users-host-manager-readd.xml");
+        try (PrintWriter writer = new PrintWriter(configFile)) {
+            writer.write(TestManagerWebapp.CONFIG);
+        }
+        addDeleteOnTearDown(configFile);
+
+        MemoryRealm memoryRealm = new MemoryRealm();
+        memoryRealm.setCredentialHandler(new MessageDigestCredentialHandler());
+        memoryRealm.setPathname(configFile.getAbsolutePath());
+        tomcat.getEngine().setRealm(memoryRealm);
+
+        File confFolder = new File(getTemporaryDirectory(), "conf");
+        confFolder.mkdirs();
+        File webappDir = new File(getBuildDirectory(), "webapps");
+
+        File appDir = new File(webappDir, "host-manager");
+        tomcat.addWebapp(null, "/host-manager", appDir.getAbsolutePath());
+
+        getProgrammaticRootContext();
+
+        tomcat.start();
+
+        SimpleHttpClient client = new SimpleHttpClient() {
+            @Override
+            public boolean isResponseBodyOK() {
+                return true;
+            }
+        };
+        client.setPort(getPort());
+        String basicHeader = (new BasicAuthHeader("Basic", "admin", 
"sekr3t")).getHeader().toString();
+
+        // @formatter:off
+        client.setRequest(new String[] {
+                "GET /host-manager/text/add?name=rehost&manager=true HTTP/1.1" 
+ CRLF +
+                    "Host: localhost" + CRLF +
+                    "Authorization: " + basicHeader + CRLF +
+                    "Connection: Close" + CRLF +
+                    CRLF
+                });
+        // @formatter:on
+        client.connect();
+        client.processRequest(true);
+        Assert.assertEquals(HttpServletResponse.SC_OK, client.getStatusCode());
+        Assert.assertTrue(client.getResponseBody(),
+                client.getResponseBody().contains("OK - Host [rehost] added"));
+        File managerXml = new File(confFolder, tomcat.getEngine().getName() + 
"/rehost/manager.xml");
+        Assert.assertTrue(managerXml.getAbsolutePath(), managerXml.isFile());
+
+        // @formatter:off
+        client.setRequest(new String[] {
+                "GET /host-manager/text/remove?name=rehost HTTP/1.1" + CRLF +
+                    "Host: localhost" + CRLF +
+                    "Authorization: " + basicHeader + CRLF +
+                    "Connection: Close" + CRLF +
+                    CRLF
+                });
+        // @formatter:on
+        client.connect();
+        client.processRequest(true);
+        Assert.assertEquals(HttpServletResponse.SC_OK, client.getStatusCode());
+        Assert.assertTrue(client.getResponseBody(),
+                client.getResponseBody().contains("OK - Removed host 
[rehost]"));
+        // The configuration directory is intentionally left in place
+        Assert.assertTrue(managerXml.getAbsolutePath(), managerXml.isFile());
+
+        // @formatter:off
+        client.setRequest(new String[] {
+                "GET /host-manager/text/add?name=rehost&manager=true HTTP/1.1" 
+ CRLF +
+                    "Host: localhost" + CRLF +
+                    "Authorization: " + basicHeader + CRLF +
+                    "Connection: Close" + CRLF +
+                    CRLF
+                });
+        // @formatter:on
+        client.connect();
+        client.processRequest(true);
+        Assert.assertEquals(HttpServletResponse.SC_OK, client.getStatusCode());
+        Assert.assertTrue(client.getResponseBody(),
+                client.getResponseBody().contains("OK - Host [rehost] added"));
+
+        tomcat.stop();
+    }
 }


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

Reply via email to