From 8f113001edc9f55f0924b634b6dcc8930f1de0e8 Mon Sep 17 00:00:00 2001 From: gapra Date: Wed, 18 Nov 2020 12:54:46 -0800 Subject: [PATCH 1/2] Fixed query param parsing bug --- .../storage/blob/ContainerAPITest.groovy | 16 +++ ...tainerAPITestlistblobsprefixwithcomma.json | 112 ++++++++++++++++++ .../implementation/StorageImplUtils.java | 13 +- 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestlistblobsprefixwithcomma.json diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy index 9342fabf9e83c..c61edbdd6f6cb 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy @@ -28,7 +28,9 @@ import com.azure.storage.blob.options.BlobSetAccessTierOptions import com.azure.storage.blob.options.PageBlobCreateOptions import com.azure.storage.blob.specialized.AppendBlobClient import com.azure.storage.blob.specialized.BlobClientBase +import com.azure.storage.common.StorageSharedKeyCredential import com.azure.storage.common.Utility +import com.azure.storage.common.implementation.StorageImplUtils import reactor.test.StepVerifier import spock.lang.Requires import spock.lang.Unroll @@ -909,6 +911,20 @@ class ContainerAPITest extends APISpec { .verifyComplete() } + def "List blobs prefix with comma"() { + setup: + def prefix = generateBlobName() + ", " + generateBlobName() + def b = cc.getBlobClient(prefix).getBlockBlobClient() + b.upload(defaultInputStream.get(), defaultData.remaining()) + + when: + ListBlobsOptions options = new ListBlobsOptions().setPrefix(prefix) + def blob = cc.listBlobs(options, null).iterator().next() + + then: + blob.getName() == prefix + } + def "List blobs flat options fail"() { when: new ListBlobsOptions().setMaxResultsPerPage(0) diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestlistblobsprefixwithcomma.json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestlistblobsprefixwithcomma.json new file mode 100644 index 0000000000000..ec53974375a26 --- /dev/null +++ b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestlistblobsprefixwithcomma.json @@ -0,0 +1,112 @@ +{ + "networkCallRecords" : [ { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/jtclistblobsprefixwithcomma097102c4f575e414a74be?restype=container", + "Headers" : { + "x-ms-version" : "2020-02-10", + "User-Agent" : "azsdk-java-azure-storage-blob/12.10.0-beta.1 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "4197dd95-684f-4280-af03-5754c699537a" + }, + "Response" : { + "x-ms-version" : "2020-02-10", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "ETag" : "0x8D88C040CD150A7", + "Last-Modified" : "Wed, 18 Nov 2020 20:53:49 GMT", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "201", + "x-ms-request-id" : "5a0b9c11-c01e-0073-35ec-bd7d3a000000", + "Date" : "Wed, 18 Nov 2020 20:53:49 GMT", + "x-ms-client-request-id" : "4197dd95-684f-4280-af03-5754c699537a" + }, + "Exception" : null + }, { + "Method" : "PUT", + "Uri" : "https://REDACTED.blob.core.windows.net/jtclistblobsprefixwithcomma097102c4f575e414a74be/javabloblistblobsprefixwithcomma199461a7d43fde3c03%2C%20javabloblistblobsprefixwithcomma235482222869197945", + "Headers" : { + "x-ms-version" : "2020-02-10", + "User-Agent" : "azsdk-java-azure-storage-blob/12.10.0-beta.1 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "e98643a2-72d7-4436-89f2-2cdac3d230c2", + "Content-Type" : "application/octet-stream" + }, + "Response" : { + "x-ms-version" : "2020-02-10", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-content-crc64" : "6RYQPwaVsyQ=", + "Last-Modified" : "Wed, 18 Nov 2020 20:53:50 GMT", + "x-ms-version-id" : "2020-11-18T20:53:50.0957813Z", + "retry-after" : "0", + "StatusCode" : "201", + "x-ms-request-server-encrypted" : "true", + "Date" : "Wed, 18 Nov 2020 20:53:50 GMT", + "Content-MD5" : "wh+Wm18D0z1D4E+PE252gg==", + "ETag" : "0x8D88C040D212075", + "Content-Length" : "0", + "x-ms-request-id" : "5a0b9c51-c01e-0073-69ec-bd7d3a000000", + "x-ms-client-request-id" : "e98643a2-72d7-4436-89f2-2cdac3d230c2" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.blob.core.windows.net/jtclistblobsprefixwithcomma097102c4f575e414a74be?prefix=javabloblistblobsprefixwithcomma199461a7d43fde3c03%2C%20javabloblistblobsprefixwithcomma235482222869197945&restype=container&comp=list", + "Headers" : { + "x-ms-version" : "2020-02-10", + "User-Agent" : "azsdk-java-azure-storage-blob/12.10.0-beta.1 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "3e79fbb3-6e16-43ac-b977-91dab3004419" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2020-02-10", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "5a0b9c60-c01e-0073-74ec-bd7d3a000000", + "Body" : "javabloblistblobsprefixwithcomma199461a7d43fde3c03, javabloblistblobsprefixwithcomma235482222869197945javabloblistblobsprefixwithcomma199461a7d43fde3c03, javabloblistblobsprefixwithcomma2354822228691979452020-11-18T20:53:50.0957813ZtrueWed, 18 Nov 2020 20:53:50 GMTWed, 18 Nov 2020 20:53:50 GMT0x8D88C040D2120757application/octet-streamwh+Wm18D0z1D4E+PE252gg==Wed, 18 Nov 2020 20:53:50 GMTBlockBlobHottrueunlockedavailabletrue", + "Date" : "Wed, 18 Nov 2020 20:53:50 GMT", + "x-ms-client-request-id" : "3e79fbb3-6e16-43ac-b977-91dab3004419", + "Content-Type" : "application/xml" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.blob.core.windows.net?prefix=jtclistblobsprefixwithcomma&comp=list", + "Headers" : { + "x-ms-version" : "2020-02-10", + "User-Agent" : "azsdk-java-azure-storage-blob/12.10.0-beta.1 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "3e01836f-8769-45a6-926e-d3df8cd56a2c" + }, + "Response" : { + "Transfer-Encoding" : "chunked", + "x-ms-version" : "2020-02-10", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "x-ms-request-id" : "5a0b9c6a-c01e-0073-7bec-bd7d3a000000", + "Body" : "jtclistblobsprefixwithcommajtclistblobsprefixwithcomma097102c4f575e414a74beWed, 18 Nov 2020 20:53:49 GMT\"0x8D88C040CD150A7\"unlockedavailable$account-encryption-keyfalsefalsefalse", + "Date" : "Wed, 18 Nov 2020 20:53:50 GMT", + "x-ms-client-request-id" : "3e01836f-8769-45a6-926e-d3df8cd56a2c", + "Content-Type" : "application/xml" + }, + "Exception" : null + }, { + "Method" : "DELETE", + "Uri" : "https://REDACTED.blob.core.windows.net/jtclistblobsprefixwithcomma097102c4f575e414a74be?restype=container", + "Headers" : { + "x-ms-version" : "2020-02-10", + "User-Agent" : "azsdk-java-azure-storage-blob/12.10.0-beta.1 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "1bce1177-17a1-4aa4-b4b2-a6b84369685c" + }, + "Response" : { + "x-ms-version" : "2020-02-10", + "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "Content-Length" : "0", + "StatusCode" : "202", + "x-ms-request-id" : "5a0b9c78-c01e-0073-04ec-bd7d3a000000", + "Date" : "Wed, 18 Nov 2020 20:53:50 GMT", + "x-ms-client-request-id" : "1bce1177-17a1-4aa4-b4b2-a6b84369685c" + }, + "Exception" : null + } ], + "variables" : [ "jtclistblobsprefixwithcomma097102c4f575e414a74be", "javabloblistblobsprefixwithcomma199461a7d43fde3c03", "javabloblistblobsprefixwithcomma235482222869197945" ] +} \ No newline at end of file diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/StorageImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/StorageImplUtils.java index 86b46678d915b..121e8916b8cc7 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/StorageImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/StorageImplUtils.java @@ -63,7 +63,18 @@ public static Map parseQueryString(final String queryString) { * @return a mapping of query string pieces as key-value pairs. */ public static Map parseQueryStringSplitValues(final String queryString) { - return parseQueryStringHelper(queryString, (value) -> urlDecode(value).split(",")); + // We need to first split by comma and then decode each piece since we don't want to confuse legitimate separate + // query values from query values that container a comma. + // Example 1: prefix=a%2cb => prefix={decode(a%2cb)} => prefix={"a,b"} + // Example 2: prefix=a,b => prefix={decode(a),decode(b)} => prefix={"a", "b"} + return parseQueryStringHelper(queryString, value -> { + String[] v = value.split(","); + String[] ret = new String[v.length]; + for (int i = 0; i < v.length; i++) { + ret[i] = urlDecode(v[i]); + } + return ret; + }); } private static Map parseQueryStringHelper(final String queryString, From 90dd7681ada5f7352f7cc0894cbaee0b4629e2bd Mon Sep 17 00:00:00 2001 From: gapra Date: Wed, 18 Nov 2020 12:56:27 -0800 Subject: [PATCH 2/2] Added changelog --- sdk/storage/azure-storage-common/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/storage/azure-storage-common/CHANGELOG.md b/sdk/storage/azure-storage-common/CHANGELOG.md index 73074886b777f..217ee9a2978db 100644 --- a/sdk/storage/azure-storage-common/CHANGELOG.md +++ b/sdk/storage/azure-storage-common/CHANGELOG.md @@ -2,6 +2,7 @@ ## 12.10.0-beta.1 (Unreleased) - Added ability to specify timeout units in RequestRetryOptions. +- Fixed bug where query params were being parsed incorrectly if an encoded comma was the query value. ## 12.9.0 (2020-11-11) - GA release