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 eeb6ff9b695b5b9d2efb031ff0d2e7614cec812a
Author: opencode <[email protected]>
AuthorDate: Wed Oct 7 16:53:20 2026 +0200

    Store namespace-less WebDAV properties in DataSourcePropertyStore
    
    Node.getNamespaceURI() returns null for a property element without a
    namespace, which was passed directly into the namespace column of the
    queries. With the documented NOT NULL schema every SET, REMOVE and
    single-property PROPFIND of a namespace-less property such as a plain
    <displayname> failed with a SQLException and a 500 response, while the
    memory store handled these properties without issue.
    
    Normalise a null namespace to the empty string, which the SQL
    statements and the XMLWriter output handle consistently, making the two
    PropertyStore implementations agree.
---
 .../catalina/servlets/DataSourcePropertyStore.java | 13 +++++----
 .../catalina/servlets/TestWebdavPropertyStore.java | 33 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/servlets/DataSourcePropertyStore.java 
b/java/org/apache/catalina/servlets/DataSourcePropertyStore.java
index 47478409ce..1a7d2390c9 100644
--- a/java/org/apache/catalina/servlets/DataSourcePropertyStore.java
+++ b/java/org/apache/catalina/servlets/DataSourcePropertyStore.java
@@ -22,6 +22,7 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -45,7 +46,7 @@ import org.w3c.dom.Node;
  * A single properties table with four columns is used:
  * <ul>
  * <li>path: the resource path</li>
- * <li>namespace: the node namespace</li>
+ * <li>namespace: the node namespace, or the empty string when the property 
has no namespace</li>
  * <li>name: the local name in the namespace</li>
  * <li>node: the full serialized XML node including the name</li>
  * </ul>
@@ -265,7 +266,7 @@ public class DataSourcePropertyStore implements 
WebdavServlet.PropertyStore {
             try (Connection connection = dataSource.getConnection();
                     PreparedStatement statement = 
connection.prepareStatement(getPropertyStatement)) {
                 statement.setString(1, resource);
-                statement.setString(2, property.getNamespaceURI());
+                statement.setString(2, 
Objects.requireNonNullElse(property.getNamespaceURI(), ""));
                 statement.setString(3, property.getLocalName());
                 if (statement.execute()) {
                     ResultSet rs = statement.getResultSet();
@@ -340,7 +341,7 @@ public class DataSourcePropertyStore implements 
WebdavServlet.PropertyStore {
                         try {
                             try (PreparedStatement statement = 
connection.prepareStatement(getPropertyStatement)) {
                                 statement.setString(1, resource);
-                                statement.setString(2, node.getNamespaceURI());
+                                statement.setString(2, 
Objects.requireNonNullElse(node.getNamespaceURI(), ""));
                                 statement.setString(3, node.getLocalName());
                                 if (statement.execute()) {
                                     ResultSet rs = statement.getResultSet();
@@ -353,14 +354,14 @@ public class DataSourcePropertyStore implements 
WebdavServlet.PropertyStore {
                                 try (PreparedStatement statement = 
connection.prepareStatement(setPropertyStatement)) {
                                     statement.setString(1, serializedNode);
                                     statement.setString(2, resource);
-                                    statement.setString(3, 
node.getNamespaceURI());
+                                    statement.setString(3, 
Objects.requireNonNullElse(node.getNamespaceURI(), ""));
                                     statement.setString(4, 
node.getLocalName());
                                     statement.execute();
                                 }
                             } else {
                                 try (PreparedStatement statement = 
connection.prepareStatement(addPropertyStatement)) {
                                     statement.setString(1, resource);
-                                    statement.setString(2, 
node.getNamespaceURI());
+                                    statement.setString(2, 
Objects.requireNonNullElse(node.getNamespaceURI(), ""));
                                     statement.setString(3, 
node.getLocalName());
                                     statement.setString(4, serializedNode);
                                     statement.execute();
@@ -376,7 +377,7 @@ public class DataSourcePropertyStore implements 
WebdavServlet.PropertyStore {
                         Node node = operation.getPropertyNode();
                         try (PreparedStatement statement = 
connection.prepareStatement(removePropertyStatement)) {
                             statement.setString(1, resource);
-                            statement.setString(2, node.getNamespaceURI());
+                            statement.setString(2, 
Objects.requireNonNullElse(node.getNamespaceURI(), ""));
                             statement.setString(3, node.getLocalName());
                             statement.execute();
                         } catch (SQLException e) {
diff --git a/test/org/apache/catalina/servlets/TestWebdavPropertyStore.java 
b/test/org/apache/catalina/servlets/TestWebdavPropertyStore.java
index 651c198f71..65b79f17c7 100644
--- a/test/org/apache/catalina/servlets/TestWebdavPropertyStore.java
+++ b/test/org/apache/catalina/servlets/TestWebdavPropertyStore.java
@@ -33,6 +33,8 @@ import javax.sql.DataSource;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import jakarta.servlet.http.HttpServletResponse;
+
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Test;
@@ -71,6 +73,10 @@ public class TestWebdavPropertyStore extends LoggingBaseTest 
{
             "  <V:othervalue>foooooooo</V:othervalue>\n" +
             "</V:someprop>";
 
+    private static final String PROPERTY4 =
+            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" +
+            "<displayname>test value</displayname>";
+
     public static final String SIMPLE_SCHEMA =
             "CREATE TABLE webdavproperties (\n" +
             "  path         VARCHAR(1024) NOT NULL,\n" +
@@ -250,6 +256,33 @@ public class TestWebdavPropertyStore extends 
LoggingBaseTest {
         Assert.assertFalse(propertyStore.propfind("/other/path2", node1, 
false, xmlWriter9));
         Assert.assertTrue(xmlWriter9.toString().isEmpty());
 
+        // Set a property without a namespace
+        Document document4 = documentBuilder.parse(new InputSource(new 
ByteArrayInputStream(PROPERTY4.getBytes(StandardCharsets.UTF_8))));
+        Node node4 = document4.getDocumentElement();
+
+        operations = new ArrayList<>();
+        operations.add(new ProppatchOperation(PropertyUpdateType.SET, node4));
+        propertyStore.proppatch("/some/path1", operations);
+        Assert.assertEquals(HttpServletResponse.SC_OK, 
operations.get(0).getStatusCode());
+
+        XMLWriter xmlWriter10 = new XMLWriter();
+        Assert.assertTrue(propertyStore.propfind("/some/path1", node4, false, 
xmlWriter10));
+        Assert.assertTrue(xmlWriter10.toString().contains(">test value<"));
+
+        XMLWriter xmlWriter11 = new XMLWriter();
+        Assert.assertFalse(propertyStore.propfind("/some/path1", null, true, 
xmlWriter11));
+        Assert.assertTrue(xmlWriter11.toString().contains("<displayname"));
+
+        // Remove the property without a namespace
+        operations = new ArrayList<>();
+        operations.add(new ProppatchOperation(PropertyUpdateType.REMOVE, 
node4));
+        propertyStore.proppatch("/some/path1", operations);
+        Assert.assertEquals(HttpServletResponse.SC_OK, 
operations.get(0).getStatusCode());
+
+        XMLWriter xmlWriter12 = new XMLWriter();
+        Assert.assertFalse(propertyStore.propfind("/some/path1", null, true, 
xmlWriter12));
+        Assert.assertFalse(xmlWriter12.toString().contains("<displayname"));
+
         propertyStore.destroy();
 
     }


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

Reply via email to