Skip to content

Commit 696999a

Browse files
authored
List invalid xml (Azure#25092)
* Added service version. Updated sas recordings * Updated datalake version conversion * Updated customizations * Generated new code * Added code for new feature * Added tests * Moved BlobName to models package * Created BlobPrefixInternal * Added last test recordings * Fixed some ci errors * Hopefully ci fixes * Updated recordings * reverted swagger to main branch * Updated changelog
1 parent 404e93e commit 696999a

File tree

15 files changed

+382
-17
lines changed

15 files changed

+382
-17
lines changed

sdk/storage/azure-storage-blob/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## 12.15.0-beta.2 (Unreleased)
44

55
### Features Added
6+
- Added support for the 2021-02-12 service version.
7+
- Added support for listing blobs which contain invalid xml characters.
68

79
### Breaking Changes
810

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerAsyncClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,8 @@ PagedFlux<BlobItem> listBlobsHierarchyWithOptionalTimeout(String delimiter, List
10221022
: Stream.concat(
10231023
response.getValue().getSegment().getBlobItems().stream().map(ModelHelper::populateBlobItem),
10241024
response.getValue().getSegment().getBlobPrefixes().stream()
1025-
.map(blobPrefix -> new BlobItem().setName(blobPrefix.getName()).setIsPrefix(true))
1025+
.map(blobPrefix -> new BlobItem()
1026+
.setName(ModelHelper.toBlobNameString(blobPrefix.getName())).setIsPrefix(true))
10261027
).collect(Collectors.toList());
10271028

10281029
return new PagedResponseBase<>(

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageImplBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public AzureBlobStorageImplBuilder addPolicy(HttpPipelinePolicy customPolicy) {
212212
*/
213213
public AzureBlobStorageImpl buildClient() {
214214
if (version == null) {
215-
this.version = "2020-12-06";
215+
this.version = "2021-02-12";
216216
}
217217
if (pipeline == null) {
218218
this.pipeline = createHttpPipeline();

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/models/BlobHierarchyListSegment.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package com.azure.storage.blob.implementation.models;
66

77
import com.azure.core.annotation.Fluent;
8-
import com.azure.storage.blob.models.BlobPrefix;
98
import com.fasterxml.jackson.annotation.JsonProperty;
109
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
1110
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@@ -21,7 +20,7 @@ public final class BlobHierarchyListSegment {
2120
* The BlobPrefixes property.
2221
*/
2322
@JsonProperty("BlobPrefix")
24-
private List<BlobPrefix> blobPrefixes = new ArrayList<>();
23+
private List<BlobPrefixInternal> blobPrefixes = new ArrayList<>();
2524

2625
/*
2726
* The BlobItems property.
@@ -34,7 +33,7 @@ public final class BlobHierarchyListSegment {
3433
*
3534
* @return the blobPrefixes value.
3635
*/
37-
public List<BlobPrefix> getBlobPrefixes() {
36+
public List<BlobPrefixInternal> getBlobPrefixes() {
3837
return this.blobPrefixes;
3938
}
4039

@@ -44,7 +43,7 @@ public List<BlobPrefix> getBlobPrefixes() {
4443
* @param blobPrefixes the blobPrefixes value to set.
4544
* @return the BlobHierarchyListSegment object itself.
4645
*/
47-
public BlobHierarchyListSegment setBlobPrefixes(List<BlobPrefix> blobPrefixes) {
46+
public BlobHierarchyListSegment setBlobPrefixes(List<BlobPrefixInternal> blobPrefixes) {
4847
this.blobPrefixes = blobPrefixes;
4948
return this;
5049
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/models/BlobItemInternal.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public final class BlobItemInternal {
1717
* The Name property.
1818
*/
1919
@JsonProperty(value = "Name", required = true)
20-
private String name;
20+
private BlobName name;
2121

2222
/*
2323
* The Deleted property.
@@ -84,7 +84,7 @@ public final class BlobItemInternal {
8484
*
8585
* @return the name value.
8686
*/
87-
public String getName() {
87+
public BlobName getName() {
8888
return this.name;
8989
}
9090

@@ -94,7 +94,7 @@ public String getName() {
9494
* @param name the name value to set.
9595
* @return the BlobItemInternal object itself.
9696
*/
97-
public BlobItemInternal setName(String name) {
97+
public BlobItemInternal setName(BlobName name) {
9898
this.name = name;
9999
return this;
100100
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
// Code generated by Microsoft (R) AutoRest Code Generator.
4+
5+
package com.azure.storage.blob.implementation.models;
6+
7+
import com.azure.core.annotation.Fluent;
8+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
9+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
10+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
11+
12+
/** The BlobName model. */
13+
@JacksonXmlRootElement(localName = "BlobName")
14+
@Fluent
15+
public final class BlobName {
16+
/*
17+
* Indicates if the blob name is encoded.
18+
*/
19+
@JacksonXmlProperty(localName = "Encoded", isAttribute = true)
20+
private Boolean encoded;
21+
22+
/*
23+
* The name of the blob.
24+
*/
25+
@JacksonXmlText
26+
private String content;
27+
28+
/**
29+
* Get the encoded property: Indicates if the blob name is encoded.
30+
*
31+
* @return the encoded value.
32+
*/
33+
public Boolean isEncoded() {
34+
return this.encoded;
35+
}
36+
37+
/**
38+
* Set the encoded property: Indicates if the blob name is encoded.
39+
*
40+
* @param encoded the encoded value to set.
41+
* @return the BlobName object itself.
42+
*/
43+
public BlobName setEncoded(Boolean encoded) {
44+
this.encoded = encoded;
45+
return this;
46+
}
47+
48+
/**
49+
* Get the content property: The name of the blob.
50+
*
51+
* @return the content value.
52+
*/
53+
public String getContent() {
54+
return this.content;
55+
}
56+
57+
/**
58+
* Set the content property: The name of the blob.
59+
*
60+
* @param content the content value to set.
61+
* @return the BlobName object itself.
62+
*/
63+
public BlobName setContent(String content) {
64+
this.content = content;
65+
return this;
66+
}
67+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
// Code generated by Microsoft (R) AutoRest Code Generator.
4+
5+
package com.azure.storage.blob.implementation.models;
6+
7+
import com.azure.core.annotation.Fluent;
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
10+
11+
/** The BlobPrefix model. */
12+
@JacksonXmlRootElement(localName = "BlobPrefix")
13+
@Fluent
14+
public final class BlobPrefixInternal {
15+
/*
16+
* The Name property.
17+
*/
18+
@JsonProperty(value = "Name", required = true)
19+
private BlobName name;
20+
21+
/**
22+
* Get the name property: The Name property.
23+
*
24+
* @return the name value.
25+
*/
26+
public BlobName getName() {
27+
return this.name;
28+
}
29+
30+
/**
31+
* Set the name property: The Name property.
32+
*
33+
* @param name the name value to set.
34+
* @return the BlobPrefix object itself.
35+
*/
36+
public BlobPrefixInternal setName(BlobName name) {
37+
this.name = name;
38+
return this;
39+
}
40+
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/CustomHierarchicalListingDeserializer.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import com.azure.storage.blob.implementation.models.BlobHierarchyListSegment;
77
import com.azure.storage.blob.implementation.models.BlobItemInternal;
8-
import com.azure.storage.blob.models.BlobPrefix;
8+
import com.azure.storage.blob.implementation.models.BlobPrefixInternal;
99
import com.fasterxml.jackson.core.JsonParser;
1010
import com.fasterxml.jackson.core.JsonToken;
1111
import com.fasterxml.jackson.databind.DeserializationContext;
@@ -26,12 +26,12 @@ public BlobHierarchyListSegment getNullValue(DeserializationContext ctxt) {
2626
@Override
2727
public BlobHierarchyListSegment deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
2828
ArrayList<BlobItemInternal> blobItems = new ArrayList<>();
29-
ArrayList<BlobPrefix> blobPrefixes = new ArrayList<>();
29+
ArrayList<BlobPrefixInternal> blobPrefixes = new ArrayList<>();
3030

3131
JsonDeserializer<Object> blobItemDeserializer =
3232
ctxt.findRootValueDeserializer(ctxt.constructType(BlobItemInternal.class));
3333
JsonDeserializer<Object> blobPrefixDeserializer =
34-
ctxt.findRootValueDeserializer(ctxt.constructType(BlobPrefix.class));
34+
ctxt.findRootValueDeserializer(ctxt.constructType(BlobPrefixInternal.class));
3535

3636
for (JsonToken currentToken = p.nextToken(); !currentToken.name().equals("END_OBJECT");
3737
currentToken = p.nextToken()) {
@@ -41,7 +41,7 @@ public BlobHierarchyListSegment deserialize(JsonParser p, DeserializationContext
4141
if (p.getCurrentName().equals("Blob")) {
4242
blobItems.add((BlobItemInternal) blobItemDeserializer.deserialize(p, ctxt));
4343
} else if (p.getCurrentName().equals("BlobPrefix")) {
44-
blobPrefixes.add((BlobPrefix) blobPrefixDeserializer.deserialize(p, ctxt));
44+
blobPrefixes.add((BlobPrefixInternal) blobPrefixDeserializer.deserialize(p, ctxt));
4545
}
4646
}
4747

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/ModelHelper.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.azure.storage.blob.ProgressReceiver;
1313
import com.azure.storage.blob.implementation.models.BlobItemInternal;
1414
import com.azure.storage.blob.implementation.models.BlobItemPropertiesInternal;
15+
import com.azure.storage.blob.implementation.models.BlobName;
1516
import com.azure.storage.blob.implementation.models.BlobTag;
1617
import com.azure.storage.blob.implementation.models.BlobTags;
1718
import com.azure.storage.blob.implementation.models.BlobsDownloadHeaders;
@@ -31,6 +32,7 @@
3132
import com.azure.storage.blob.models.PageBlobCopyIncrementalRequestConditions;
3233
import com.azure.storage.blob.models.ParallelTransferOptions;
3334
import com.azure.storage.blob.models.TaggedBlobItem;
35+
import com.azure.storage.common.Utility;
3436
import com.azure.storage.common.implementation.Constants;
3537

3638
import java.io.IOException;
@@ -262,7 +264,7 @@ public static BlobDownloadHeaders populateBlobDownloadHeaders(
262264
*/
263265
public static BlobItem populateBlobItem(BlobItemInternal blobItemInternal) {
264266
BlobItem blobItem = new BlobItem();
265-
blobItem.setName(blobItemInternal.getName());
267+
blobItem.setName(toBlobNameString(blobItemInternal.getName()));
266268
blobItem.setDeleted(blobItemInternal.isDeleted());
267269
blobItem.setSnapshot(blobItemInternal.getSnapshot());
268270
blobItem.setProperties(populateBlobItemProperties(blobItemInternal.getProperties()));
@@ -281,6 +283,12 @@ public static BlobItem populateBlobItem(BlobItemInternal blobItemInternal) {
281283
return blobItem;
282284
}
283285

286+
public static String toBlobNameString(BlobName blobName) {
287+
return blobName.isEncoded() != null && blobName.isEncoded()
288+
? Utility.urlDecode(blobName.getContent())
289+
: blobName.getContent();
290+
}
291+
284292
public static TaggedBlobItem populateTaggedBlobItem(FilterBlobItem filterBlobItem) {
285293
return new TaggedBlobItem(filterBlobItem.getContainerName(), filterBlobItem.getName(),
286294
tagMapFromBlobTags(filterBlobItem.getTags()));

sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,19 @@ class ContainerAPITest extends APISpec {
10671067
RehydratePriority.HIGH || _
10681068
}
10691069

1070+
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "V2021_02_12")
1071+
def "List blobs flat invalid xml"() {
1072+
setup:
1073+
def blobName = "dir1/dir2/file\uFFFE.blob";
1074+
cc.getBlobClient(blobName).getAppendBlobClient().create()
1075+
1076+
when:
1077+
def blobItem = cc.listBlobs().iterator().next()
1078+
1079+
then:
1080+
blobItem.getName() == blobName
1081+
}
1082+
10701083
def "List blobs flat error"() {
10711084
setup:
10721085
cc = primaryBlobServiceClient.getBlobContainerClient(generateContainerName())
@@ -1120,6 +1133,7 @@ class ContainerAPITest extends APISpec {
11201133
This test requires two accounts that are configured in a very specific way. It is not feasible to setup that
11211134
relationship programmatically, so we have recorded a successful interaction and only test recordings.
11221135
*/
1136+
11231137
@PlaybackOnly
11241138
def "List blobs flat ORS"() {
11251139
setup:
@@ -1436,6 +1450,7 @@ class ContainerAPITest extends APISpec {
14361450
This test requires two accounts that are configured in a very specific way. It is not feasible to setup that
14371451
relationship programmatically, so we have recorded a successful interaction and only test recordings.
14381452
*/
1453+
14391454
@PlaybackOnly
14401455
def "List blobs hier ORS"() {
14411456
setup:
@@ -1546,6 +1561,30 @@ class ContainerAPITest extends APISpec {
15461561
blob.getProperties().isSealed()
15471562
}
15481563

1564+
@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "V2021_02_12")
1565+
def "List blobs hier invalid xml"() {
1566+
setup:
1567+
def blobName = 'dir1/dir2/file\uFFFE.blob';
1568+
cc.getBlobClient(blobName).getAppendBlobClient().create()
1569+
1570+
when:
1571+
def blobItem
1572+
if (!delimiter) {
1573+
blobItem = cc.listBlobsByHierarchy("", null, null).iterator().next()
1574+
} else {
1575+
blobItem = cc.listBlobsByHierarchy(".b", null, null).iterator().next()
1576+
}
1577+
1578+
then:
1579+
blobItem.getName() == (delimiter ? "dir1/dir2/file\uFFFE.b" : blobName)
1580+
blobItem.isPrefix() == (delimiter ? true : null)
1581+
1582+
where:
1583+
delimiter | _
1584+
false | _
1585+
true | _
1586+
}
1587+
15491588
def "List blobs hier error"() {
15501589
setup:
15511590
cc = primaryBlobServiceClient.getBlobContainerClient(generateContainerName())
@@ -1583,7 +1622,7 @@ class ContainerAPITest extends APISpec {
15831622

15841623
where:
15851624
name | _
1586-
"中文" | _
1625+
"中文" | _
15871626
"az[]" | _
15881627
"hello world" | _
15891628
"hello/world" | _

0 commit comments

Comments
 (0)