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

ChenSammi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new e62ad5b37af HDDS-16248. Refactor 
PutBucketLifecycleConfigurationUnmarshaller to extend MessageUnmarshaller 
(#11075)
e62ad5b37af is described below

commit e62ad5b37afca7ac2baef2489f15aa9674ce76a6
Author: Sammi Chen <[email protected]>
AuthorDate: Tue Aug 25 16:32:59 2026 +0800

    HDDS-16248. Refactor PutBucketLifecycleConfigurationUnmarshaller to extend 
MessageUnmarshaller (#11075)
---
 .../ozone/s3/endpoint/BucketLifecycleHandler.java  |  3 +-
 ...utBucketLifecycleConfigurationUnmarshaller.java | 56 +-------------
 ...utBucketLifecycleConfigurationUnmarshaller.java | 86 ++++++++++++++++++++++
 3 files changed, 90 insertions(+), 55 deletions(-)

diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
index cf4270f925b..f25ea9d8b89 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketLifecycleHandler.java
@@ -133,8 +133,7 @@ public Response 
putBucketLifecycleConfiguration(S3RequestContext context, String
     OzoneBucket ozoneBucket = context.getVolume().getBucket(bucketName);
     OmLifecycleConfiguration lcc;
     try {
-      s3LifecycleConfiguration = new 
PutBucketLifecycleConfigurationUnmarshaller().readFrom(null,
-          null, null, null, null, body);
+      s3LifecycleConfiguration = new 
PutBucketLifecycleConfigurationUnmarshaller().readFrom(body);
       lcc = s3LifecycleConfiguration.toOmLifecycleConfiguration(ozoneBucket);
     } catch (WebApplicationException ex) {
       throw S3ErrorTable.newError(S3ErrorTable.MALFORMED_XML, bucketName);
diff --git 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/PutBucketLifecycleConfigurationUnmarshaller.java
 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/PutBucketLifecycleConfigurationUnmarshaller.java
index 6cf28a7c12f..36da3bde2de 100644
--- 
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/PutBucketLifecycleConfigurationUnmarshaller.java
+++ 
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/PutBucketLifecycleConfigurationUnmarshaller.java
@@ -17,64 +17,14 @@
 
 package org.apache.hadoop.ozone.s3.endpoint;
 
-import static org.apache.hadoop.ozone.s3.util.S3Consts.S3_XML_NAMESPACE;
-
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyReader;
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.UnmarshallerHandler;
-import javax.xml.parsers.SAXParserFactory;
-import org.xml.sax.InputSource;
-import org.xml.sax.XMLReader;
-
 /**
- * Custom unmarshaller to read Lifecycle configuration namespace.
+ * Custom unmarshaller to read Lifecycle configuration.
  */
 public class PutBucketLifecycleConfigurationUnmarshaller
-    implements MessageBodyReader<S3LifecycleConfiguration>  {
-
-  private final JAXBContext context;
-  private final XMLReader xmlReader;
+    extends MessageUnmarshaller<S3LifecycleConfiguration> {
 
   public PutBucketLifecycleConfigurationUnmarshaller() {
-    try {
-      context = JAXBContext.newInstance(S3LifecycleConfiguration.class);
-      SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
-      saxParserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 
true);
-      xmlReader = saxParserFactory.newSAXParser().getXMLReader();
-    } catch (Exception ex) {
-      throw new AssertionError("Can not instantiate " +
-          "PutBucketLifecycleConfiguration parser", ex);
-    }
+    super(S3LifecycleConfiguration.class);
   }
 
-  @Override
-  public boolean isReadable(Class<?> type, Type genericType,
-      Annotation[] annotations, MediaType mediaType) {
-    return type.equals(S3LifecycleConfiguration.class);
-  }
-
-  @Override
-  public S3LifecycleConfiguration readFrom(Class<S3LifecycleConfiguration> 
type,
-      Type genericType, Annotation[] annotations, MediaType mediaType,
-      MultivaluedMap<String, String> httpHeaders, InputStream inputStream)
-      throws WebApplicationException {
-    try {
-      UnmarshallerHandler unmarshallerHandler =
-          context.createUnmarshaller().getUnmarshallerHandler();
-      XmlNamespaceFilter filter = new XmlNamespaceFilter(S3_XML_NAMESPACE);
-      filter.setContentHandler(unmarshallerHandler);
-      filter.setParent(xmlReader);
-      filter.parse(new InputSource(inputStream));
-      return (S3LifecycleConfiguration)(unmarshallerHandler.getResult());
-    } catch (Exception e) {
-      throw new WebApplicationException("Can't parse request body to XML.", e);
-    }
-  }
 }
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPutBucketLifecycleConfigurationUnmarshaller.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPutBucketLifecycleConfigurationUnmarshaller.java
new file mode 100644
index 00000000000..76c67c5e3da
--- /dev/null
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPutBucketLifecycleConfigurationUnmarshaller.java
@@ -0,0 +1,86 @@
+/*
+ * 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.hadoop.ozone.s3.endpoint;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import javax.ws.rs.WebApplicationException;
+import org.apache.hadoop.ozone.s3.util.S3Consts;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests XML parsing for {@link PutBucketLifecycleConfigurationUnmarshaller}.
+ */
+public class TestPutBucketLifecycleConfigurationUnmarshaller {
+
+  @Test
+  public void fromStreamWithNamespace() {
+    ByteArrayInputStream inputBody = new ByteArrayInputStream(
+        ("<LifecycleConfiguration xmlns=\"" + S3Consts.S3_XML_NAMESPACE + 
"\">" +
+            "<Rule>" +
+            "<ID>expire after 1 day</ID>" +
+            "<Status>Enabled</Status>" +
+            "<Expiration><Days>1</Days></Expiration>" +
+            "</Rule>" +
+            "</LifecycleConfiguration>")
+            .getBytes(UTF_8));
+
+    S3LifecycleConfiguration configuration =
+        new PutBucketLifecycleConfigurationUnmarshaller().readFrom(inputBody);
+
+    assertNotNull(configuration);
+    assertEquals(1, configuration.getRules().size());
+    assertEquals("expire after 1 day", 
configuration.getRules().get(0).getId());
+  }
+
+  @Test
+  public void lifecycleXmlWithDoctypeIsRejected() {
+    String xml = "<?xml version=\"1.0\"?>\n"
+        + "<!DOCTYPE LifecycleConfiguration ["
+        + "<!ENTITY xxe SYSTEM \"file:///etc/passwd\">]>\n"
+        + "<LifecycleConfiguration xmlns=\"" + S3Consts.S3_XML_NAMESPACE + 
"\">"
+        + "<Rule>"
+        + "<ID>rule1</ID>"
+        + "<Status>Enabled</Status>"
+        + "<Expiration><Days>1</Days></Expiration>"
+        + "</Rule>"
+        + "</LifecycleConfiguration>";
+
+    WebApplicationException ex = assertThrows(WebApplicationException.class,
+        () -> new PutBucketLifecycleConfigurationUnmarshaller()
+            .readFrom(new ByteArrayInputStream(xml.getBytes(UTF_8))));
+
+    assertTrue(containsDisallowDoctypeDecl(ex),
+        "Expected parser to reject DOCTYPE declarations");
+  }
+
+  private static boolean containsDisallowDoctypeDecl(Throwable throwable) {
+    for (Throwable current = throwable; current != null; current = 
current.getCause()) {
+      if (current.getMessage() != null
+          && current.getMessage().contains("disallow-doctype-decl")) {
+        return true;
+      }
+    }
+    return false;
+  }
+}


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

Reply via email to