Skip to content
Permalink
Browse files
Parse out of order ListBuckets response elements
Currently, jclouds assumes that the ListBuckets response follows a
specific order: the <Owner> tag, followed by the <Buckets> tag. Within
the <Owner> tag, jclouds further assumes that the <ID> must occur before
the <DisplayName> tag. If the XML body does not adhere to this order,
the parser throws a NullPointerException.

DigitalOcean spaces does not adhere to this order and returns the
<DisplayName> tag before the <ID> tag. The patch changes the parser to
not depend on the order of the tags.
  • Loading branch information
timuralp authored and gaul committed Apr 4, 2021
1 parent c995a04 commit 04feb8f8482e48b6c26166edb3d6fd5a607d858b
Showing 3 changed files with 40 additions and 2 deletions.
@@ -23,9 +23,11 @@
* <p/>
*/
public class CanonicalUser {
private final String id;
private String id;
private String displayName;

public CanonicalUser() {}

public CanonicalUser(String id) {
this.id = id;
}
@@ -44,6 +46,8 @@ public String getId() {
return id;
}

public void setId(String id) { this.id = id; }

/**
* read-only as is maintained by Amazon.
*/
@@ -39,6 +39,7 @@ public class ListAllMyBucketsHandler extends ParseSax.HandlerWithResult<Set<Buck

private Set<BucketMetadata> buckets = Sets.newLinkedHashSet();
private CanonicalUser currentOwner;
private String currentDisplayName;
private StringBuilder currentText = new StringBuilder();

private final DateService dateParser;
@@ -48,6 +49,7 @@ public class ListAllMyBucketsHandler extends ParseSax.HandlerWithResult<Set<Buck
@Inject
public ListAllMyBucketsHandler(DateService dateParser) {
this.dateParser = dateParser;
this.currentOwner = new CanonicalUser();
}

public Set<BucketMetadata> getResult() {
@@ -56,7 +58,7 @@ public Set<BucketMetadata> getResult() {

public void endElement(String uri, String name, String qName) {
if (qName.equals("ID")) { // owner stuff
currentOwner = new CanonicalUser(currentOrNull(currentText));
currentOwner.setId(currentOrNull(currentText));
} else if (qName.equals("DisplayName")) {
currentOwner.setDisplayName(currentOrNull(currentText));
} else if (qName.equals("Bucket")) {
@@ -70,6 +70,8 @@ protected void tearDownInjector() {
}

public static final String listAllMyBucketsResultOn200 = "<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/callables/\"><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID></Owner><Buckets><Bucket><Name>adrianjbosstest</Name><CreationDate>2009-03-12T02:00:07.000Z</CreationDate></Bucket><Bucket><Name>adrianjbosstest2</Name><CreationDate>2009-03-12T02:00:09.000Z</CreationDate></Bucket></Buckets></ListAllMyBucketsResult>";
public static final String listAllMyBucketsResultOn200DisplayNameFirst = "<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/callables/\"><Owner><DisplayName>TestName</DisplayName><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID></Owner><Buckets><Bucket><Name>adrianjbosstest</Name><CreationDate>2009-03-12T02:00:07.000Z</CreationDate></Bucket></Buckets></ListAllMyBucketsResult>";
public static final String listAllMyBucketsResultOn200OwnerLast = "<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/callables/\"><Buckets><Bucket><Name>adrianjbosstest</Name><CreationDate>2009-03-12T02:00:07.000Z</CreationDate></Bucket></Buckets><Owner><DisplayName>TestName</DisplayName><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID></Owner></ListAllMyBucketsResult>";

@Test
void testParseListAllMyBucketsSerialResponseTime() throws HttpException {
@@ -114,6 +116,36 @@ public void testCanParseListAllMyBuckets() throws HttpException {
assert container2.getOwner().equals(owner);
}

@Test
public void testCanParseListAllMyBucketsDisplayNameFirst() throws HttpException {
Set<BucketMetadata> s3Buckets = factory.create(injector.getInstance(ListAllMyBucketsHandler.class)).parse(
Strings2.toInputStream(listAllMyBucketsResultOn200DisplayNameFirst));
BucketMetadata container = Iterables.get(s3Buckets, 0);
assert container.getName().equals("adrianjbosstest");
Date expectedDate1 = new SimpleDateFormatDateService().iso8601DateParse("2009-03-12T02:00:07.000Z");
Date date = container.getCreationDate();
assert date.equals(expectedDate1);
assert s3Buckets.size() == 1;
CanonicalUser owner = new CanonicalUser("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0",
"TestName");
assert container.getOwner().equals(owner);
}

@Test
public void testCanParseListAllMyBucketsOwnerLast() throws HttpException {
Set<BucketMetadata> s3Buckets = factory.create(injector.getInstance(ListAllMyBucketsHandler.class)).parse(
Strings2.toInputStream(listAllMyBucketsResultOn200OwnerLast));
BucketMetadata container = Iterables.get(s3Buckets, 0);
assert container.getName().equals("adrianjbosstest");
Date expectedDate = new SimpleDateFormatDateService().iso8601DateParse("2009-03-12T02:00:07.000Z");
Date date1 = container.getCreationDate();
assert date1.equals(expectedDate);
assert s3Buckets.size() == 1;
CanonicalUser owner = new CanonicalUser("e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0",
"TestName");
assert container.getOwner().equals(owner);
}

public static final String listContainerResult = "<ListContainerHandler xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>adrianjbosstest</Name><Prefix></Prefix><Marker></Marker><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><Key>3366</Key><LastModified>2009-03-12T02:00:13.000Z</LastModified><ETag>&quot;9d7bb64e8e18ee34eec06dd2cf37b766&quot;</ETag><Size>136</Size><Owner><ID>e1a5f66a480ca99a4fdfe8e318c3020446c9989d7004e7778029fbcc5d990fa0</ID><DisplayName>ferncam</DisplayName></Owner><StorageClass>STANDARD</StorageClass></Contents></ListContainerHandler>";

public void testCanParseListContainerResult() throws HttpException {

0 comments on commit 04feb8f

Please sign in to comment.