From a3bca2124d256fd547550ff6b64f27e9e99dbd00 Mon Sep 17 00:00:00 2001 From: Priyesh Karatha Date: Thu, 23 Jul 2026 20:41:38 +0530 Subject: [PATCH] HDDS-15950. Fix NPE in S3 lifecycle GET for date-based expiration --- .../s3/endpoint/S3LifecycleConfiguration.java | 5 +-- .../TestS3LifecycleConfigurationGet.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java index ff72a322dee3..de1de9616a74 100644 --- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java +++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java @@ -479,7 +479,7 @@ private static Expiration convertFromOzoneExpiration( if (date != null && !date.isEmpty()) { expiration.setDate(date); } - if (ozoneExpiration.getDays() > 0) { + if (ozoneExpiration.getDays() != null && ozoneExpiration.getDays() > 0) { expiration.setDays(ozoneExpiration.getDays()); } @@ -497,7 +497,8 @@ private static AbortIncompleteMultipartUpload convertFromOzoneAbortIncompleteMul AbortIncompleteMultipartUpload abortIncompleteMultipartUpload = new AbortIncompleteMultipartUpload(); - if (ozoneAbortIncompleteMultipartUpload.getDaysAfterInitiation() > 0) { + if (ozoneAbortIncompleteMultipartUpload.getDaysAfterInitiation() != null + && ozoneAbortIncompleteMultipartUpload.getDaysAfterInitiation() > 0) { abortIncompleteMultipartUpload.setDaysAfterInitiation( ozoneAbortIncompleteMultipartUpload.getDaysAfterInitiation()); } diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationGet.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationGet.java index 0558af9c1f8c..8e4d0eb88ada 100644 --- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationGet.java +++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationGet.java @@ -21,6 +21,7 @@ import static java.net.HttpURLConnection.HTTP_OK; import static org.apache.hadoop.ozone.s3.exception.S3ErrorTable.NO_SUCH_LIFECYCLE_CONFIGURATION; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.fail; import java.io.ByteArrayInputStream; @@ -124,6 +125,24 @@ public void testGetLifecycleWithBothActions() throws Exception { .getDaysAfterInitiation().intValue()); } + @Test + public void testGetLifecycleWithDateBasedExpiration() throws Exception { + String bucketName = "bucket1"; + bucketEndpoint.put(bucketName, getBodyWithDateExpiration()); + Response r = bucketEndpoint.get(bucketName); + + assertEquals(HTTP_OK, r.getStatus()); + S3LifecycleConfiguration lcc = (S3LifecycleConfiguration) r.getEntity(); + assertEquals(1, lcc.getRules().size()); + S3LifecycleConfiguration.Rule rule = lcc.getRules().get(0); + + assertEquals("expire-on-date", rule.getId()); + assertEquals("prefix/", rule.getPrefix()); + assertEquals("Enabled", rule.getStatus()); + assertEquals("2044-01-19T00:00:00+00:00", rule.getExpiration().getDate()); + assertNull(rule.getExpiration().getDays()); + } + private static InputStream getBody() { String xml = ("" + @@ -153,6 +172,19 @@ private static InputStream getBodyWithAbortAction() { return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); } + private static InputStream getBodyWithDateExpiration() { + String xml = "" + + "" + + "expire-on-date" + + "prefix/" + + "Enabled" + + "2044-01-19T00:00:00+00:00" + + "" + + ""; + + return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); + } + private static InputStream getBodyWithBothActions() { String xml = "" + "" +