From 3e15d92ce8d8ec4eae958a2ecf4c1c0d35a4c456 Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Sat, 22 Aug 2020 21:02:30 +0800 Subject: [PATCH 01/10] [Storage] Custom domain support. --- sdk/storage/storage-blob/src/Clients.ts | 20 ++++++++--- .../storage-blob/src/utils/utils.common.ts | 29 ++++++++++----- .../storage-blob/test/blobclient.spec.ts | 7 ++++ .../test/blobserviceclient.spec.ts | 5 +++ .../storage-blob/test/containerclient.spec.ts | 6 ++++ .../src/utils/utils.common.ts | 26 ++++++++++---- .../src/utils/utils.common.ts | 36 +++++++++++++------ .../test/directoryclient.spec.ts | 19 ++++++++++ .../test/fileclient.spec.ts | 19 ++++++++++ .../test/shareclient.spec.ts | 13 +++++-- ...stom_endpoint_without_valid_accountname.js | 5 +++ sdk/storage/storage-queue/src/QueueClient.ts | 7 +++- .../storage-queue/src/utils/utils.common.ts | 25 +++++++++---- .../storage-queue/test/queueclient.spec.ts | 6 ++++ .../test/queueserviceclient.spec.ts | 5 +++ 15 files changed, 189 insertions(+), 39 deletions(-) create mode 100644 sdk/storage/storage-queue/recordings/node/queueserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js diff --git a/sdk/storage/storage-blob/src/Clients.ts b/sdk/storage/storage-blob/src/Clients.ts index d1874cb87105..aab28f8a3e47 100644 --- a/sdk/storage/storage-blob/src/Clients.ts +++ b/sdk/storage/storage-blob/src/Clients.ts @@ -112,10 +112,11 @@ import { ETagNone } from "./utils/constants"; import { - setURLParameter, - extractConnectionStringParts, appendToURLPath, + extractConnectionStringParts, generateBlockID, + isIpEndpointStyle, + setURLParameter, toBlobTagsString, toQuerySerialization, truncatedISO8061Date, @@ -2196,13 +2197,19 @@ export class BlobClient extends StorageClient { const pathComponents = parsedUrl.getPath()!.match("/([^/]*)(/(.*))?"); containerName = pathComponents![1]; blobName = pathComponents![3]; - } else { + } else if (isIpEndpointStyle(parsedUrl.getHost()! + (parsedUrl.getPort() == undefined ? '' : ':' + parsedUrl.getPort()))) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/containername/blob // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/containername/blob // .getPath() -> /devstoreaccount1/containername/blob const pathComponents = parsedUrl.getPath()!.match("/([^/]*)/([^/]*)(/(.*))?"); containerName = pathComponents![2]; blobName = pathComponents![4]; + } else { + // "https://customdomain.com/containername/blob". + // .getPath() -> /containername/blob + const pathComponents = parsedUrl.getPath()!.match("/([^/]*)(/(.*))?"); + containerName = pathComponents![1]; + blobName = pathComponents![3]; } // decode the encoded blobName, containerName - to get all the special characters that might be present in them @@ -7910,13 +7917,18 @@ export class ContainerClient extends StorageClient { if (parsedUrl.getHost()!.split(".")[1] === "blob") { // "https://myaccount.blob.core.windows.net/containername". + // "https://customdomain.com/containername". // .getPath() -> /containername containerName = parsedUrl.getPath()!.split("/")[1]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/containername // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/containername // .getPath() -> /devstoreaccount1/containername containerName = parsedUrl.getPath()!.split("/")[2]; + } else { + // "https://customdomain.com/containername". + // .getPath() -> /containername + containerName = parsedUrl.getPath()!.split("/")[1]; } // decode the encoded containerName - to get all the special characters that might be present in it diff --git a/sdk/storage/storage-blob/src/utils/utils.common.ts b/sdk/storage/storage-blob/src/utils/utils.common.ts index 3889ffa0d62d..417fa93bf7c9 100644 --- a/sdk/storage/storage-blob/src/utils/utils.common.ts +++ b/sdk/storage/storage-blob/src/utils/utils.common.ts @@ -186,19 +186,17 @@ export function extractConnectionStringParts(connectionString: string): Connecti url: blobEndpoint, accountName, accountKey, - proxyUri + proxyUri, }; } else { // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getAccountNameFromUrl(blobEndpoint); + let accountName = getValueInConnString(connectionString, "AccountName"); if (!blobEndpoint) { throw new Error("Invalid BlobEndpoint in the provided SAS Connection String"); } else if (!accountSas) { throw new Error("Invalid SharedAccessSignature in the provided SAS Connection String"); - } else if (!accountName) { - throw new Error("Invalid AccountName in the provided SAS Connection String"); } return { kind: "SASConnString", url: blobEndpoint, accountName, accountSas }; @@ -541,15 +539,14 @@ export function getAccountNameFromUrl(url: string): string { if (parsedUrl.getHost()!.split(".")[1] === "blob") { // `${defaultEndpointsProtocol}://${accountName}.blob.${endpointSuffix}`; accountName = parsedUrl.getHost()!.split(".")[0]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/ // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/ // .getPath() -> /devstoreaccount1/ accountName = parsedUrl.getPath()!.split("/")[1]; - } - - if (!accountName) { - throw new Error("Provided accountName is invalid."); + } else { + // Custom domain case: "https://customdomain.com/containername/blob". + accountName = ''; } return accountName; } catch (error) { @@ -557,6 +554,20 @@ export function getAccountNameFromUrl(url: string): string { } } +export function isIpEndpointStyle(parsedUrl: URLBuilder): boolean { + if (parsedUrl.getHost() == undefined) { + return false; + } + + const host = parsedUrl.getHost()! + (parsedUrl.getPort() == undefined ? '' : ':' + parsedUrl.getPort()); + + // Case 1: Ipv6, use a broad regex to find out candidates whose host contains two ':'. + // Case 2: localhost(:port), use broad regex to match port part. + // Case 3: Ipv4, use broad regex which just check if host contains Ipv4. + // For valid host please refer to https://man7.org/linux/man-pages/man7/hostname.7.html. + return /^.*:.*:.*$|^localhost(:[0-9]+)?$|^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}(:[0-9]+)?$/.test(host); +} + /** * Convert Tags to encoded string. * diff --git a/sdk/storage/storage-blob/test/blobclient.spec.ts b/sdk/storage/storage-blob/test/blobclient.spec.ts index ebe6cae78938..3991b2e3b1dd 100644 --- a/sdk/storage/storage-blob/test/blobclient.spec.ts +++ b/sdk/storage/storage-blob/test/blobclient.spec.ts @@ -844,4 +844,11 @@ describe("BlobClient - Verify Name Properties", () => { it("verify endpoint without dots", async () => { verifyNameProperties(`https://localhost:80/${accountName}/${containerName}/${blobName}`); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new BlobClient(`https://customdomain.com/${containerName}/${blobName}`); + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + assert.equal(newClient.containerName, containerName, "Container name is not the same as the one provided."); + assert.equal(newClient.name, blobName, "Blob name is not the same as the one provided."); + }); }); diff --git a/sdk/storage/storage-blob/test/blobserviceclient.spec.ts b/sdk/storage/storage-blob/test/blobserviceclient.spec.ts index 677da322e472..c4cfab16e471 100644 --- a/sdk/storage/storage-blob/test/blobserviceclient.spec.ts +++ b/sdk/storage/storage-blob/test/blobserviceclient.spec.ts @@ -537,4 +537,9 @@ describe("BlobServiceClient", () => { await containerClient.delete(); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new BlobServiceClient(`https://customdomain.com`); + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + }); }); diff --git a/sdk/storage/storage-blob/test/containerclient.spec.ts b/sdk/storage/storage-blob/test/containerclient.spec.ts index 2dcbf5ee6947..16d6b87aaeed 100644 --- a/sdk/storage/storage-blob/test/containerclient.spec.ts +++ b/sdk/storage/storage-blob/test/containerclient.spec.ts @@ -827,4 +827,10 @@ describe("ContainerClient - Verify Name Properties", () => { it("verify endpoint without dots", async () => { verifyNameProperties(`https://localhost:80/${accountName}/${containerName}`); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new ContainerClient(`https://customdomain.com/${containerName}`); + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + assert.equal(newClient.containerName, containerName, "Container name is not the same as the one provided."); + }); }); diff --git a/sdk/storage/storage-file-datalake/src/utils/utils.common.ts b/sdk/storage/storage-file-datalake/src/utils/utils.common.ts index ace1439f22dd..d37be3ae787f 100644 --- a/sdk/storage/storage-file-datalake/src/utils/utils.common.ts +++ b/sdk/storage/storage-file-datalake/src/utils/utils.common.ts @@ -188,13 +188,11 @@ export function extractConnectionStringParts(connectionString: string): Connecti // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getAccountNameFromUrl(blobEndpoint); + let accountName = getValueInConnString(connectionString, "AccountName"); if (!blobEndpoint) { throw new Error("Invalid BlobEndpoint in the provided SAS Connection String"); } else if (!accountSas) { throw new Error("Invalid SharedAccessSignature in the provided SAS Connection String"); - } else if (!accountName) { - throw new Error("Invalid AccountName in the provided SAS Connection String"); } return { kind: "SASConnString", url: blobEndpoint, accountName, accountSas }; @@ -551,18 +549,32 @@ export function getAccountNameFromUrl(blobEndpointUrl: string): string { if (parsedUrl.getHost()!.split(".")[1] === "blob") { // `${defaultEndpointsProtocol}://${accountName}.blob.${endpointSuffix}`; accountName = parsedUrl.getHost()!.split(".")[0]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/ // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/ // .getPath() -> /devstoreaccount1/ accountName = parsedUrl.getPath()!.split("/")[1]; + } else { + // Custom domain case: "https://customdomain.com/containername/blob". + accountName = ''; } - if (!accountName) { - throw new Error("Provided accountName is invalid."); - } return accountName; } catch (error) { throw new Error("Unable to extract accountName with provided information."); } } + +export function isIpEndpointStyle(parsedUrl: URLBuilder): boolean { + if (parsedUrl.getHost() == undefined) { + return false; + } + + const host = parsedUrl.getHost()! + (parsedUrl.getPort() == undefined ? '' : ':' + parsedUrl.getPort()); + + // Case 1: Ipv6, use a broad regex to find out candidates whose host contains two ':'. + // Case 2: localhost(:port), use broad regex to match port part. + // Case 3: Ipv4, use broad regex which just check if host contains Ipv4. + // For valid host please refer to https://man7.org/linux/man-pages/man7/hostname.7.html. + return /^.*:.*:.*$|^localhost(:[0-9]+)?$|^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}(:[0-9]+)?$/.test(host); +} diff --git a/sdk/storage/storage-file-share/src/utils/utils.common.ts b/sdk/storage/storage-file-share/src/utils/utils.common.ts index 8d48620ce474..4c3835362a11 100644 --- a/sdk/storage/storage-file-share/src/utils/utils.common.ts +++ b/sdk/storage/storage-file-share/src/utils/utils.common.ts @@ -160,15 +160,12 @@ export function extractConnectionStringParts(connectionString: string): Connecti }; } else { // SAS connection string - - let accountName = getAccountNameFromUrl(fileEndpoint); let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); + let accountName = getValueInConnString(connectionString, "AccountName"); if (!fileEndpoint) { throw new Error("Invalid FileEndpoint in the provided SAS Connection String"); } else if (!accountSas) { throw new Error("Invalid SharedAccessSignature in the provided SAS Connection String"); - } else if (!accountName) { - throw new Error("Invalid AccountName in the provided SAS Connection String"); } return { kind: "SASConnString", url: fileEndpoint, accountName, accountSas }; @@ -441,15 +438,14 @@ export function getAccountNameFromUrl(url: string): string { url = url.endsWith("/") ? url.slice(0, -1) : url; accountName = parsedUrl.getHost()!.split(".")[0]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/ // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/ // .getPath() -> /devstoreaccount1/ accountName = parsedUrl.getPath()!.split("/")[1]; - } - - if (!accountName) { - throw new Error("Provided accountName is invalid."); + } else { + // Custom domain case: "https://customdomain.com/containername/blob". + accountName = ''; } return accountName; } catch (error) { @@ -457,6 +453,20 @@ export function getAccountNameFromUrl(url: string): string { } } +export function isIpEndpointStyle(parsedUrl: URLBuilder): boolean { + if (parsedUrl.getHost() == undefined) { + return false; + } + + const host = parsedUrl.getHost()! + (parsedUrl.getPort() == undefined ? '' : ':' + parsedUrl.getPort()); + + // Case 1: Ipv6, use a broad regex to find out candidates whose host contains two ':'. + // Case 2: localhost(:port), use broad regex to match port part. + // Case 3: Ipv4, use broad regex which just check if host contains Ipv4. + // For valid host please refer to https://man7.org/linux/man-pages/man7/hostname.7.html. + return /^.*:.*:.*$|^localhost(:[0-9]+)?$|^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}(:[0-9]+)?$/.test(host); +} + export function getShareNameAndPathFromUrl( url: string ): { baseName: string; shareName: string; path: string } { @@ -483,13 +493,19 @@ export function getShareNameAndPathFromUrl( const pathComponents = parsedUrl.getPath()!.match("/([^/]*)(/(.*))?"); shareName = pathComponents![1]; path = pathComponents![3]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://187.24.0.1:1000/devstoreaccount1/mydirectory/file // Single word domain without a [dot] in the endpoint... Example - http://localhost:1000/devstoreaccount1/mydirectory/file // .getPath() -> /devstoreaccount1/mydirectory/file const pathComponents = parsedUrl.getPath()!.match("/([^/]*)/([^/]*)(/(.*))?"); shareName = pathComponents![2]; path = pathComponents![4]; + } else { + // "https://customdomain.com/myshare/mydirectory/file"; + // .getPath() -> /myshare/mydirectory/file + const pathComponents = parsedUrl.getPath()!.match("/([^/]*)(/(.*))?"); + shareName = pathComponents![1]; + path = pathComponents![3]; } // decode the encoded shareName and filePath - to get all the special characters that might be present in it diff --git a/sdk/storage/storage-file-share/test/directoryclient.spec.ts b/sdk/storage/storage-file-share/test/directoryclient.spec.ts index 1c1d161628bb..d3c98a458f58 100644 --- a/sdk/storage/storage-file-share/test/directoryclient.spec.ts +++ b/sdk/storage/storage-file-share/test/directoryclient.spec.ts @@ -912,4 +912,23 @@ describe("ShareDirectoryClient - Verify Name Properties", () => { it("verify endpoint without dots", async () => { verifyNameProperties(`https://localhost:80/${accountName}/${shareName}/${dirPath}/${baseName}`); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new ShareDirectoryClient( + `https://customdomain.com/${shareName}/${dirPath}/${baseName}` + ); + + assert.equal(newClient.accountName, "", "Account name is not the same as the one provided."); + assert.equal(newClient.shareName, shareName, "Share name is not the same as the one provided."); + assert.equal( + newClient.path, + dirPath + "/" + baseName, + "DirPath is not the same as the one provided." + ); + assert.equal( + newClient.name, + baseName, + "DirectoryClient name is not the same as the baseName of the provided directory URI" + ); + }); }); diff --git a/sdk/storage/storage-file-share/test/fileclient.spec.ts b/sdk/storage/storage-file-share/test/fileclient.spec.ts index 08a233c29ce0..f490c036a128 100644 --- a/sdk/storage/storage-file-share/test/fileclient.spec.ts +++ b/sdk/storage/storage-file-share/test/fileclient.spec.ts @@ -818,4 +818,23 @@ describe("ShareFileClient - Verify Name Properties", () => { it("verify endpoint without dots", async () => { verifyNameProperties(`https://localhost:80/${accountName}/${shareName}/${dirName}/${fileName}`); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new ShareFileClient( + `https://customdomain.com/${shareName}/${dirName}/${fileName}` + ); + + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + assert.equal(newClient.shareName, shareName, "Share name is not the same as the one provided."); + assert.equal( + newClient.path, + dirName + "/" + fileName, + "FilePath is not the same as the one provided." + ); + assert.equal( + newClient.name, + fileName, + "FileClient name is not the same as the baseName of the provided file URI" + ); + }); }); diff --git a/sdk/storage/storage-file-share/test/shareclient.spec.ts b/sdk/storage/storage-file-share/test/shareclient.spec.ts index 4bffc887ddd0..f9029f304e89 100644 --- a/sdk/storage/storage-file-share/test/shareclient.spec.ts +++ b/sdk/storage/storage-file-share/test/shareclient.spec.ts @@ -12,7 +12,7 @@ describe("ShareClient", () => { let recorder: Recorder; - beforeEach(async function() { + beforeEach(async function () { recorder = record(this, recorderEnvSetup); serviceClient = getBSU(); shareName = recorder.getUniqueName("share"); @@ -20,7 +20,7 @@ describe("ShareClient", () => { await shareClient.create(); }); - afterEach(async function() { + afterEach(async function () { await shareClient.delete(); await recorder.stop(); }); @@ -262,4 +262,13 @@ describe("ShareDirectoryClient - Verify Name Properties", () => { it("verify endpoint without dots", async () => { verifyNameProperties(`https://localhost:80/${accountName}/${shareName}`); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new ShareClient( + `https://customdomain.com/${shareName}` + ); + + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + assert.equal(newClient.name, shareName, "Share name is not the same as the one provided."); + }); }); diff --git a/sdk/storage/storage-queue/recordings/node/queueserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js b/sdk/storage/storage-queue/recordings/node/queueserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js new file mode 100644 index 000000000000..76f15d60e58a --- /dev/null +++ b/sdk/storage/storage-queue/recordings/node/queueserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "1940db747dc8462148d8b7062ddc46b5"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-queue/src/QueueClient.ts b/sdk/storage/storage-queue/src/QueueClient.ts index dddcfe982cfa..bec226efbd58 100644 --- a/sdk/storage/storage-queue/src/QueueClient.ts +++ b/sdk/storage/storage-queue/src/QueueClient.ts @@ -38,6 +38,7 @@ import { StorageClient, CommonOptions } from "./StorageClient"; import { appendToURLPath, extractConnectionStringParts, + isIpEndpointStyle, truncatedISO8061Date, getStorageClientContext } from "./utils/utils.common"; @@ -1313,11 +1314,15 @@ export class QueueClient extends StorageClient { // "https://myaccount.queue.core.windows.net/queuename". // .getPath() -> /queuename queueName = parsedUrl.getPath()!.split("/")[1]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/queuename // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/queuename // .getPath() -> /devstoreaccount1/queuename queueName = parsedUrl.getPath()!.split("/")[2]; + } else { + // "https://customdomain.com/queuename". + // .getPath() -> /queuename + queueName = parsedUrl.getPath()!.split("/")[1]; } if (!queueName) { diff --git a/sdk/storage/storage-queue/src/utils/utils.common.ts b/sdk/storage/storage-queue/src/utils/utils.common.ts index e44a3d833b43..85a2d2a752c0 100644 --- a/sdk/storage/storage-queue/src/utils/utils.common.ts +++ b/sdk/storage/storage-queue/src/utils/utils.common.ts @@ -239,7 +239,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getAccountNameFromUrl(queueEndpoint); + let accountName = getValueInConnString(connectionString, "AccountName"); if (!queueEndpoint) { throw new Error("Invalid QueueEndpoint in the provided SAS Connection String"); } else if (!accountSas) { @@ -379,15 +379,14 @@ export function getAccountNameFromUrl(url: string): string { if (parsedUrl.getHost()!.split(".")[1] === "queue") { // `${defaultEndpointsProtocol}://${accountName}.queue.${endpointSuffix}`; accountName = parsedUrl.getHost()!.split(".")[0]; - } else { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/ // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/ // .getPath() -> /devstoreaccount1/ accountName = parsedUrl.getPath()!.split("/")[1]; - } - - if (!accountName) { - throw new Error("Provided accountName is invalid."); + } else { + // Custom domain case: "https://customdomain.com/containername/blob". + accountName = ''; } return accountName; } catch (error) { @@ -395,6 +394,20 @@ export function getAccountNameFromUrl(url: string): string { } } +export function isIpEndpointStyle(parsedUrl: URLBuilder): boolean { + if (parsedUrl.getHost() == undefined) { + return false; + } + + const host = parsedUrl.getHost()! + (parsedUrl.getPort() == undefined ? '' : ':' + parsedUrl.getPort()); + + // Case 1: Ipv6, use a broad regex to find out candidates whose host contains two ':'. + // Case 2: localhost(:port), use broad regex to match port part. + // Case 3: Ipv4, use broad regex which just check if host contains Ipv4. + // For valid host please refer to https://man7.org/linux/man-pages/man7/hostname.7.html. + return /^.*:.*:.*$|^localhost(:[0-9]+)?$|^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])){3}(:[0-9]+)?$/.test(host); +} + /** * Gets a new StorageClientContext * @param {string} url Url used for the StorageClientContext diff --git a/sdk/storage/storage-queue/test/queueclient.spec.ts b/sdk/storage/storage-queue/test/queueclient.spec.ts index bb38005fbde2..3da09b30f6a6 100644 --- a/sdk/storage/storage-queue/test/queueclient.spec.ts +++ b/sdk/storage/storage-queue/test/queueclient.spec.ts @@ -277,4 +277,10 @@ describe("QueueClient - Verify Name Properties", () => { queueName ); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new QueueClient(`https://customdomain.com/${queueName}`); + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + assert.equal(newClient.name, queueName, "Queue name is not the same as the one provided."); + }); }); diff --git a/sdk/storage/storage-queue/test/queueserviceclient.spec.ts b/sdk/storage/storage-queue/test/queueserviceclient.spec.ts index ba31da668c21..0a68b29b2ecd 100644 --- a/sdk/storage/storage-queue/test/queueserviceclient.spec.ts +++ b/sdk/storage/storage-queue/test/queueserviceclient.spec.ts @@ -371,4 +371,9 @@ describe("QueueServiceClient", () => { assert.equal(err.details.errorCode, "QueueNotFound", "Error does not contain details property"); assert.ok(err.message.includes("QueueNotFound"), "Error doesn't say `QueueNotFound`"); }); + + it("verify custom endpoint without valid accountName", async () => { + const newClient = new QueueServiceClient(`https://customdomain.com/`); + assert.equal(newClient.accountName, "", "Account name is not the same as expected."); + }); }); From 71da09846d02e547874884aca7ec937049ed2b79 Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Sat, 22 Aug 2020 21:42:15 +0800 Subject: [PATCH 02/10] Fix build error. --- sdk/storage/storage-blob/src/Clients.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/storage-blob/src/Clients.ts b/sdk/storage/storage-blob/src/Clients.ts index aab28f8a3e47..42e51edb34ff 100644 --- a/sdk/storage/storage-blob/src/Clients.ts +++ b/sdk/storage/storage-blob/src/Clients.ts @@ -2197,7 +2197,7 @@ export class BlobClient extends StorageClient { const pathComponents = parsedUrl.getPath()!.match("/([^/]*)(/(.*))?"); containerName = pathComponents![1]; blobName = pathComponents![3]; - } else if (isIpEndpointStyle(parsedUrl.getHost()! + (parsedUrl.getPort() == undefined ? '' : ':' + parsedUrl.getPort()))) { + } else if (isIpEndpointStyle(parsedUrl)) { // IPv4/IPv6 address hosts... Example - http://192.0.0.10:10001/devstoreaccount1/containername/blob // Single word domain without a [dot] in the endpoint... Example - http://localhost:10001/devstoreaccount1/containername/blob // .getPath() -> /devstoreaccount1/containername/blob From 8829e5e969ad5973eadf0c6c2583424ea29c6857 Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Sun, 23 Aug 2020 21:00:40 +0800 Subject: [PATCH 03/10] Add recording files. --- ...rding_verify_custom_endpoint_without_valid_accountname.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js diff --git a/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js b/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js new file mode 100644 index 000000000000..7633643fb482 --- /dev/null +++ b/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "226964620fa7c0e1df4a1d658a8ad466"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} From 599903ff1a48e804645e48edbf5c0739f8acc41d Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Sun, 23 Aug 2020 21:05:14 +0800 Subject: [PATCH 04/10] Add recording files. --- ...ording_verify_custom_endpoint_without_valid_accountname.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js b/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js index 7633643fb482..0801158cd310 100644 --- a/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js +++ b/sdk/storage/storage-blob/recordings/node/blobserviceclient/recording_verify_custom_endpoint_without_valid_accountname.js @@ -1,5 +1,5 @@ -let nock = require('nock'); +let nock = require("nock"); module.exports.hash = "226964620fa7c0e1df4a1d658a8ad466"; -module.exports.testInfo = {"uniqueName":{},"newDate":{}} +module.exports.testInfo = { uniqueName: {}, newDate: {} }; From 04a877db92215722e9f1eed7e305c125715f077b Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Mon, 24 Aug 2020 18:51:05 +0800 Subject: [PATCH 05/10] Add test cases for custom domain connection string. --- sdk/storage/storage-blob/CHANGELOG.md | 1 + sdk/storage/storage-blob/test/utils.spec.ts | 44 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/sdk/storage/storage-blob/CHANGELOG.md b/sdk/storage/storage-blob/CHANGELOG.md index 53fd8a4b548b..e0ba6adbd526 100644 --- a/sdk/storage/storage-blob/CHANGELOG.md +++ b/sdk/storage/storage-blob/CHANGELOG.md @@ -3,6 +3,7 @@ ## 12.2.0 (Unreleased) - Added RehydratePriority to BlobProperties and BlobItemProperties. +- Added custom domain support. ## 12.2.0-preview.1 (2020.07) diff --git a/sdk/storage/storage-blob/test/utils.spec.ts b/sdk/storage/storage-blob/test/utils.spec.ts index 8002aadc7a0d..1360c225abfd 100644 --- a/sdk/storage/storage-blob/test/utils.spec.ts +++ b/sdk/storage/storage-blob/test/utils.spec.ts @@ -13,6 +13,7 @@ describe("Utility Helpers", () => { const endpointSuffix = "core.windows.net"; const accountName = "myaccount"; const blobEndpoint = `${protocol}://${accountName}.blob.${endpointSuffix}`; + const customDomainBlobEndpoint = `${protocol}://customdomain.com`; const sharedAccessSignature = "sasToken"; function verifySASConnectionString(sasConnectionString: string) { @@ -78,4 +79,47 @@ describe("Utility Helpers", () => { SharedAccessSignature=${sharedAccessSignature}` ); }); + + it("extractConnectionStringParts parses sas connection string with custom domain", async () => { + const sasConnectionString = `BlobEndpoint=${customDomainBlobEndpoint}; + SharedAccessSignature=${sharedAccessSignature}` + const connectionStringParts = extractConnectionStringParts(sasConnectionString); + assert.equal( + "SASConnString", + connectionStringParts.kind, + "extractConnectionStringParts().kind is different than expected." + ); + assert.equal( + customDomainBlobEndpoint, + connectionStringParts.url, + "extractConnectionStringParts().url is different than expected." + ); + assert.equal( + '', + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); + }); + + it("extractConnectionStringParts parses sas connection string with custom domain", async () => { + const sasConnectionString = `BlobEndpoint=${customDomainBlobEndpoint}; + SharedAccessSignature=${sharedAccessSignature}; + AccountName=${accountName}` + const connectionStringParts = extractConnectionStringParts(sasConnectionString); + assert.equal( + "SASConnString", + connectionStringParts.kind, + "extractConnectionStringParts().kind is different than expected." + ); + assert.equal( + customDomainBlobEndpoint, + connectionStringParts.url, + "extractConnectionStringParts().url is different than expected." + ); + assert.equal( + accountName, + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); + }); }); From 694ef0d709b596f53e098a99f099c44ee2ecb73b Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Tue, 25 Aug 2020 11:39:04 +0800 Subject: [PATCH 06/10] Add test case for isIpEndpointStyle. --- sdk/storage/storage-blob/test/utils.spec.ts | 47 ++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/sdk/storage/storage-blob/test/utils.spec.ts b/sdk/storage/storage-blob/test/utils.spec.ts index 1360c225abfd..005ad84c4113 100644 --- a/sdk/storage/storage-blob/test/utils.spec.ts +++ b/sdk/storage/storage-blob/test/utils.spec.ts @@ -4,8 +4,10 @@ import { HttpHeaders } from "../src"; import { sanitizeHeaders, sanitizeURL, - extractConnectionStringParts + extractConnectionStringParts, + isIpEndpointStyle } from "../src/utils/utils.common"; +import { URLBuilder } from "@azure/core-http"; dotenv.config(); describe("Utility Helpers", () => { @@ -122,4 +124,47 @@ describe("Utility Helpers", () => { "extractConnectionStringParts().accountName is different than expected." ); }); + + it("isIpEndpointStyle", async () => { + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://192.0.0.10:1900/accountName/containerName/blobName") + ), + true + ); + assert.equal( + isIpEndpointStyle( + URLBuilder.parse( + "https://[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443/accountName/containerName/blobName" + ) + ), + true + ); + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://localhost:80/accountName/containerName/blobName") + ), + true + ); + + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://192.0.0.10:1900/")), true); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://192.0.0.10")), true); + + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://2001:db8:85a3:8d3:1319:8a2e:370:7348/accountName/containerName") + ), + true + ); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://2001::1")), true); + // assert.equal(isIpEndpointStyle(URLBuilder.parse('https://::1')), true); currently not working due to http url.ts's issue. uncomment after core lib fixed. + + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://a.b.c.d")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://256.1.1.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.256.1.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255.256.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255.255.256")), false); + }); }); From 19fc5703f1d511eb7d47b80d686b20b03400dbe4 Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Tue, 25 Aug 2020 13:58:27 +0800 Subject: [PATCH 07/10] Fix SAS connection string account name parse issue. --- .../storage-blob/src/utils/utils.common.ts | 2 +- sdk/storage/storage-blob/test/utils.spec.ts | 29 ++++--------------- .../src/utils/utils.common.ts | 2 +- .../storage-file-datalake/test/utils.spec.ts | 5 ++++ .../src/utils/utils.common.ts | 2 +- .../storage-file-share/test/utils.spec.ts | 5 ++++ .../storage-queue/src/utils/utils.common.ts | 2 +- sdk/storage/storage-queue/test/utils.spec.ts | 5 ++++ 8 files changed, 25 insertions(+), 27 deletions(-) diff --git a/sdk/storage/storage-blob/src/utils/utils.common.ts b/sdk/storage/storage-blob/src/utils/utils.common.ts index 417fa93bf7c9..de12593321a2 100644 --- a/sdk/storage/storage-blob/src/utils/utils.common.ts +++ b/sdk/storage/storage-blob/src/utils/utils.common.ts @@ -192,7 +192,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getValueInConnString(connectionString, "AccountName"); + let accountName = getAccountNameFromUrl(blobEndpoint); if (!blobEndpoint) { throw new Error("Invalid BlobEndpoint in the provided SAS Connection String"); } else if (!accountSas) { diff --git a/sdk/storage/storage-blob/test/utils.spec.ts b/sdk/storage/storage-blob/test/utils.spec.ts index 005ad84c4113..82695b335c71 100644 --- a/sdk/storage/storage-blob/test/utils.spec.ts +++ b/sdk/storage/storage-blob/test/utils.spec.ts @@ -15,7 +15,7 @@ describe("Utility Helpers", () => { const endpointSuffix = "core.windows.net"; const accountName = "myaccount"; const blobEndpoint = `${protocol}://${accountName}.blob.${endpointSuffix}`; - const customDomainBlobEndpoint = `${protocol}://customdomain.com`; + const customDomainBlobEndpoint = `${protocol}://customdomain.com`; const sharedAccessSignature = "sasToken"; function verifySASConnectionString(sasConnectionString: string) { @@ -30,6 +30,11 @@ describe("Utility Helpers", () => { connectionStringParts.url, "extractConnectionStringParts().url is different than expected." ); + assert.equal( + accountName, + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); } it("sanitizeURL redacts SAS token", () => { @@ -103,28 +108,6 @@ describe("Utility Helpers", () => { ); }); - it("extractConnectionStringParts parses sas connection string with custom domain", async () => { - const sasConnectionString = `BlobEndpoint=${customDomainBlobEndpoint}; - SharedAccessSignature=${sharedAccessSignature}; - AccountName=${accountName}` - const connectionStringParts = extractConnectionStringParts(sasConnectionString); - assert.equal( - "SASConnString", - connectionStringParts.kind, - "extractConnectionStringParts().kind is different than expected." - ); - assert.equal( - customDomainBlobEndpoint, - connectionStringParts.url, - "extractConnectionStringParts().url is different than expected." - ); - assert.equal( - accountName, - connectionStringParts.accountName, - "extractConnectionStringParts().accountName is different than expected." - ); - }); - it("isIpEndpointStyle", async () => { assert.equal( isIpEndpointStyle( diff --git a/sdk/storage/storage-file-datalake/src/utils/utils.common.ts b/sdk/storage/storage-file-datalake/src/utils/utils.common.ts index d37be3ae787f..a3c0c4bed7ce 100644 --- a/sdk/storage/storage-file-datalake/src/utils/utils.common.ts +++ b/sdk/storage/storage-file-datalake/src/utils/utils.common.ts @@ -188,7 +188,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getValueInConnString(connectionString, "AccountName"); + let accountName = getAccountNameFromUrl(blobEndpoint); if (!blobEndpoint) { throw new Error("Invalid BlobEndpoint in the provided SAS Connection String"); } else if (!accountSas) { diff --git a/sdk/storage/storage-file-datalake/test/utils.spec.ts b/sdk/storage/storage-file-datalake/test/utils.spec.ts index 15a6b413e6d2..f8582e1679ee 100644 --- a/sdk/storage/storage-file-datalake/test/utils.spec.ts +++ b/sdk/storage/storage-file-datalake/test/utils.spec.ts @@ -30,6 +30,11 @@ describe("Utility Helpers", () => { connectionStringParts.url, "extractConnectionStringParts().url is different than expected." ); + assert.equal( + accountName, + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); } beforeEach(function() { diff --git a/sdk/storage/storage-file-share/src/utils/utils.common.ts b/sdk/storage/storage-file-share/src/utils/utils.common.ts index 4c3835362a11..d9f63a22335c 100644 --- a/sdk/storage/storage-file-share/src/utils/utils.common.ts +++ b/sdk/storage/storage-file-share/src/utils/utils.common.ts @@ -161,7 +161,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti } else { // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getValueInConnString(connectionString, "AccountName"); + let accountName = getAccountNameFromUrl(blobEndpoint); if (!fileEndpoint) { throw new Error("Invalid FileEndpoint in the provided SAS Connection String"); } else if (!accountSas) { diff --git a/sdk/storage/storage-file-share/test/utils.spec.ts b/sdk/storage/storage-file-share/test/utils.spec.ts index a2c7ce8cc57c..b1d364fec1ca 100644 --- a/sdk/storage/storage-file-share/test/utils.spec.ts +++ b/sdk/storage/storage-file-share/test/utils.spec.ts @@ -30,6 +30,11 @@ describe("Utility Helpers", () => { connectionStringParts.url, "extractConnectionStringParts().url is different than expected." ); + assert.equal( + accountName, + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); } beforeEach(async function() { diff --git a/sdk/storage/storage-queue/src/utils/utils.common.ts b/sdk/storage/storage-queue/src/utils/utils.common.ts index 85a2d2a752c0..2ec0eee54358 100644 --- a/sdk/storage/storage-queue/src/utils/utils.common.ts +++ b/sdk/storage/storage-queue/src/utils/utils.common.ts @@ -239,7 +239,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getValueInConnString(connectionString, "AccountName"); + let accountName = getAccountNameFromUrl(blobEndpoint); if (!queueEndpoint) { throw new Error("Invalid QueueEndpoint in the provided SAS Connection String"); } else if (!accountSas) { diff --git a/sdk/storage/storage-queue/test/utils.spec.ts b/sdk/storage/storage-queue/test/utils.spec.ts index 5dcb58f94a60..d4a2c22c6eef 100644 --- a/sdk/storage/storage-queue/test/utils.spec.ts +++ b/sdk/storage/storage-queue/test/utils.spec.ts @@ -30,6 +30,11 @@ describe("Utility Helpers", () => { connectionStringParts.url, "extractConnectionStringParts().url is different than expected." ); + assert.equal( + accountName, + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); } beforeEach(async function() { From 24f1834008ab227b60bfd11d6cee056585c702e8 Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Tue, 25 Aug 2020 14:29:43 +0800 Subject: [PATCH 08/10] Add more test cases. --- ..._connection_string_with_custom_domain.json | 8 ++ .../recording_isipendpointstyle.json | 8 ++ ...as_connection_string_with_custom_domain.js | 5 ++ .../recording_isipendpointstyle.js | 5 ++ .../src/utils/utils.common.ts | 2 +- .../storage-file-share/test/utils.spec.ts | 73 ++++++++++++++++++- ..._connection_string_with_custom_domain.json | 8 ++ .../recording_isipendpointstyle.json | 8 ++ ...as_connection_string_with_custom_domain.js | 5 ++ .../recording_isipendpointstyle.js | 5 ++ .../storage-queue/src/utils/utils.common.ts | 2 +- sdk/storage/storage-queue/test/utils.spec.ts | 73 ++++++++++++++++++- 12 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json create mode 100644 sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_isipendpointstyle.json create mode 100644 sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js create mode 100644 sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_isipendpointstyle.js create mode 100644 sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json create mode 100644 sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_isipendpointstyle.json create mode 100644 sdk/storage/storage-queue/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js create mode 100644 sdk/storage/storage-queue/recordings/node/utility_helpers/recording_isipendpointstyle.js diff --git a/sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json b/sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json new file mode 100644 index 000000000000..f45e6b8cc3db --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json @@ -0,0 +1,8 @@ +{ + "recordings": [], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "d97fdc31fadf1daea54fd464240c523f" +} \ No newline at end of file diff --git a/sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_isipendpointstyle.json b/sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_isipendpointstyle.json new file mode 100644 index 000000000000..1c9ce5ce8eec --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/browsers/utility_helpers/recording_isipendpointstyle.json @@ -0,0 +1,8 @@ +{ + "recordings": [], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "35e088368f2950a9658b70aa8468bb96" +} \ No newline at end of file diff --git a/sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js b/sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js new file mode 100644 index 000000000000..46a0ab156496 --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "7d0138b1f70985bc6cc8ac00b0e1cd07"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_isipendpointstyle.js b/sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_isipendpointstyle.js new file mode 100644 index 000000000000..e37ec191e4db --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/node/utility_helpers/recording_isipendpointstyle.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "41f6091844c03df58994c6bea06f5989"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-file-share/src/utils/utils.common.ts b/sdk/storage/storage-file-share/src/utils/utils.common.ts index d9f63a22335c..88ad71ca0c24 100644 --- a/sdk/storage/storage-file-share/src/utils/utils.common.ts +++ b/sdk/storage/storage-file-share/src/utils/utils.common.ts @@ -161,7 +161,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti } else { // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getAccountNameFromUrl(blobEndpoint); + let accountName = getAccountNameFromUrl(fileEndpoint); if (!fileEndpoint) { throw new Error("Invalid FileEndpoint in the provided SAS Connection String"); } else if (!accountSas) { diff --git a/sdk/storage/storage-file-share/test/utils.spec.ts b/sdk/storage/storage-file-share/test/utils.spec.ts index b1d364fec1ca..2d8f159f5e18 100644 --- a/sdk/storage/storage-file-share/test/utils.spec.ts +++ b/sdk/storage/storage-file-share/test/utils.spec.ts @@ -4,10 +4,12 @@ import { HttpHeaders } from "../src"; import { sanitizeHeaders, sanitizeURL, - extractConnectionStringParts + extractConnectionStringParts, + isIpEndpointStyle } from "../src/utils/utils.common"; import { record, Recorder } from "@azure/test-utils-recorder"; import { recorderEnvSetup } from "./utils"; +import { URLBuilder } from "@azure/core-http"; dotenv.config(); describe("Utility Helpers", () => { @@ -16,6 +18,7 @@ describe("Utility Helpers", () => { const endpointSuffix = "core.windows.net"; const accountName = "myaccount"; const fileEndpoint = `${protocol}://${accountName}.file.${endpointSuffix}`; + const customDomainFileEndpoint = `${protocol}://customdomain.com`; const sharedAccessSignature = "sasToken"; function verifySASConnectionString(sasConnectionString: string) { @@ -37,11 +40,11 @@ describe("Utility Helpers", () => { ); } - beforeEach(async function() { + beforeEach(async function () { recorder = record(this, recorderEnvSetup); }); - afterEach(async function() { + afterEach(async function () { await recorder.stop(); }); @@ -94,4 +97,68 @@ describe("Utility Helpers", () => { SharedAccessSignature=${sharedAccessSignature}` ); }); + + it.only("extractConnectionStringParts parses sas connection string with custom domain", async () => { + const sasConnectionString = `FileEndpoint=${customDomainFileEndpoint}; + SharedAccessSignature=${sharedAccessSignature}` + const connectionStringParts = extractConnectionStringParts(sasConnectionString); + assert.equal( + "SASConnString", + connectionStringParts.kind, + "extractConnectionStringParts().kind is different than expected." + ); + assert.equal( + customDomainFileEndpoint, + connectionStringParts.url, + "extractConnectionStringParts().url is different than expected." + ); + assert.equal( + '', + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); + }); + + it.only("isIpEndpointStyle", async () => { + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://192.0.0.10:1900/accountName/containerName/blobName") + ), + true + ); + assert.equal( + isIpEndpointStyle( + URLBuilder.parse( + "https://[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443/accountName/containerName/blobName" + ) + ), + true + ); + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://localhost:80/accountName/containerName/blobName") + ), + true + ); + + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://192.0.0.10:1900/")), true); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://192.0.0.10")), true); + + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://2001:db8:85a3:8d3:1319:8a2e:370:7348/accountName/containerName") + ), + true + ); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://2001::1")), true); + // assert.equal(isIpEndpointStyle(URLBuilder.parse('https://::1')), true); currently not working due to http url.ts's issue. uncomment after core lib fixed. + + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://a.b.c.d")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://256.1.1.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.256.1.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255.256.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255.255.256")), false); + }); }); diff --git a/sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json b/sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json new file mode 100644 index 000000000000..83b23529339c --- /dev/null +++ b/sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.json @@ -0,0 +1,8 @@ +{ + "recordings": [], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "f452f11ed12e2b630ad521a290010ef9" +} \ No newline at end of file diff --git a/sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_isipendpointstyle.json b/sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_isipendpointstyle.json new file mode 100644 index 000000000000..8b83b161bb37 --- /dev/null +++ b/sdk/storage/storage-queue/recordings/browsers/utility_helpers/recording_isipendpointstyle.json @@ -0,0 +1,8 @@ +{ + "recordings": [], + "uniqueTestInfo": { + "uniqueName": {}, + "newDate": {} + }, + "hash": "4a9bf82b4c70af5e58d154250dd8d867" +} \ No newline at end of file diff --git a/sdk/storage/storage-queue/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js b/sdk/storage/storage-queue/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js new file mode 100644 index 000000000000..19cdc85fb958 --- /dev/null +++ b/sdk/storage/storage-queue/recordings/node/utility_helpers/recording_extractconnectionstringparts_parses_sas_connection_string_with_custom_domain.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "ae2c3c4a69d376da389d64832ac4e010"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-queue/recordings/node/utility_helpers/recording_isipendpointstyle.js b/sdk/storage/storage-queue/recordings/node/utility_helpers/recording_isipendpointstyle.js new file mode 100644 index 000000000000..e37ec191e4db --- /dev/null +++ b/sdk/storage/storage-queue/recordings/node/utility_helpers/recording_isipendpointstyle.js @@ -0,0 +1,5 @@ +let nock = require('nock'); + +module.exports.hash = "41f6091844c03df58994c6bea06f5989"; + +module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-queue/src/utils/utils.common.ts b/sdk/storage/storage-queue/src/utils/utils.common.ts index 2ec0eee54358..0ea70ef39ba5 100644 --- a/sdk/storage/storage-queue/src/utils/utils.common.ts +++ b/sdk/storage/storage-queue/src/utils/utils.common.ts @@ -239,7 +239,7 @@ export function extractConnectionStringParts(connectionString: string): Connecti // SAS connection string let accountSas = getValueInConnString(connectionString, "SharedAccessSignature"); - let accountName = getAccountNameFromUrl(blobEndpoint); + let accountName = getAccountNameFromUrl(queueEndpoint); if (!queueEndpoint) { throw new Error("Invalid QueueEndpoint in the provided SAS Connection String"); } else if (!accountSas) { diff --git a/sdk/storage/storage-queue/test/utils.spec.ts b/sdk/storage/storage-queue/test/utils.spec.ts index d4a2c22c6eef..7b650d55c03b 100644 --- a/sdk/storage/storage-queue/test/utils.spec.ts +++ b/sdk/storage/storage-queue/test/utils.spec.ts @@ -4,10 +4,12 @@ import { HttpHeaders } from "../src"; import { sanitizeHeaders, sanitizeURL, - extractConnectionStringParts + extractConnectionStringParts, + isIpEndpointStyle } from "../src/utils/utils.common"; import { record, Recorder } from "@azure/test-utils-recorder"; import { recorderEnvSetup } from "./utils/testutils.common"; +import { URLBuilder } from "@azure/core-http"; dotenv.config(); describe("Utility Helpers", () => { @@ -16,6 +18,7 @@ describe("Utility Helpers", () => { const endpointSuffix = "core.windows.net"; const accountName = "myaccount"; const queueEndpoint = `${protocol}://${accountName}.queue.${endpointSuffix}`; + const customDomainQueueEndpoint = `${protocol}://customdomain.com`; const sharedAccessSignature = "sasToken"; function verifySASConnectionString(sasConnectionString: string) { @@ -37,11 +40,11 @@ describe("Utility Helpers", () => { ); } - beforeEach(async function() { + beforeEach(async function () { recorder = record(this, recorderEnvSetup); }); - afterEach(async function() { + afterEach(async function () { await recorder.stop(); }); @@ -94,4 +97,68 @@ describe("Utility Helpers", () => { SharedAccessSignature=${sharedAccessSignature}` ); }); + + it("extractConnectionStringParts parses sas connection string with custom domain", async () => { + const sasConnectionString = `QueueEndpoint=${customDomainQueueEndpoint}; + SharedAccessSignature=${sharedAccessSignature}` + const connectionStringParts = extractConnectionStringParts(sasConnectionString); + assert.equal( + "SASConnString", + connectionStringParts.kind, + "extractConnectionStringParts().kind is different than expected." + ); + assert.equal( + customDomainQueueEndpoint, + connectionStringParts.url, + "extractConnectionStringParts().url is different than expected." + ); + assert.equal( + '', + connectionStringParts.accountName, + "extractConnectionStringParts().accountName is different than expected." + ); + }); + + it("isIpEndpointStyle", async () => { + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://192.0.0.10:1900/accountName/containerName/blobName") + ), + true + ); + assert.equal( + isIpEndpointStyle( + URLBuilder.parse( + "https://[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443/accountName/containerName/blobName" + ) + ), + true + ); + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://localhost:80/accountName/containerName/blobName") + ), + true + ); + + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://192.0.0.10:1900/")), true); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://192.0.0.10")), true); + + assert.equal( + isIpEndpointStyle( + URLBuilder.parse("https://2001:db8:85a3:8d3:1319:8a2e:370:7348/accountName/containerName") + ), + true + ); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://2001::1")), true); + // assert.equal(isIpEndpointStyle(URLBuilder.parse('https://::1')), true); currently not working due to http url.ts's issue. uncomment after core lib fixed. + + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://a.b.c.d")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://256.1.1.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.256.1.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255.256.1")), false); + assert.equal(isIpEndpointStyle(URLBuilder.parse("https://255.255.255.256")), false); + }); }); From 9249e6e63d5ee320197bfd14566e6ea5de29fc5c Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Tue, 25 Aug 2020 14:30:57 +0800 Subject: [PATCH 09/10] Run prettier. --- sdk/storage/storage-file-share/test/utils.spec.ts | 8 ++++---- sdk/storage/storage-queue/test/utils.spec.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk/storage/storage-file-share/test/utils.spec.ts b/sdk/storage/storage-file-share/test/utils.spec.ts index 2d8f159f5e18..3b710ec7794b 100644 --- a/sdk/storage/storage-file-share/test/utils.spec.ts +++ b/sdk/storage/storage-file-share/test/utils.spec.ts @@ -40,11 +40,11 @@ describe("Utility Helpers", () => { ); } - beforeEach(async function () { + beforeEach(async function() { recorder = record(this, recorderEnvSetup); }); - afterEach(async function () { + afterEach(async function() { await recorder.stop(); }); @@ -100,7 +100,7 @@ describe("Utility Helpers", () => { it.only("extractConnectionStringParts parses sas connection string with custom domain", async () => { const sasConnectionString = `FileEndpoint=${customDomainFileEndpoint}; - SharedAccessSignature=${sharedAccessSignature}` + SharedAccessSignature=${sharedAccessSignature}`; const connectionStringParts = extractConnectionStringParts(sasConnectionString); assert.equal( "SASConnString", @@ -113,7 +113,7 @@ describe("Utility Helpers", () => { "extractConnectionStringParts().url is different than expected." ); assert.equal( - '', + "", connectionStringParts.accountName, "extractConnectionStringParts().accountName is different than expected." ); diff --git a/sdk/storage/storage-queue/test/utils.spec.ts b/sdk/storage/storage-queue/test/utils.spec.ts index 7b650d55c03b..3fed1d443b6b 100644 --- a/sdk/storage/storage-queue/test/utils.spec.ts +++ b/sdk/storage/storage-queue/test/utils.spec.ts @@ -40,11 +40,11 @@ describe("Utility Helpers", () => { ); } - beforeEach(async function () { + beforeEach(async function() { recorder = record(this, recorderEnvSetup); }); - afterEach(async function () { + afterEach(async function() { await recorder.stop(); }); @@ -100,7 +100,7 @@ describe("Utility Helpers", () => { it("extractConnectionStringParts parses sas connection string with custom domain", async () => { const sasConnectionString = `QueueEndpoint=${customDomainQueueEndpoint}; - SharedAccessSignature=${sharedAccessSignature}` + SharedAccessSignature=${sharedAccessSignature}`; const connectionStringParts = extractConnectionStringParts(sasConnectionString); assert.equal( "SASConnString", @@ -113,7 +113,7 @@ describe("Utility Helpers", () => { "extractConnectionStringParts().url is different than expected." ); assert.equal( - '', + "", connectionStringParts.accountName, "extractConnectionStringParts().accountName is different than expected." ); From 1dff53b946fc9c64ada408d5a6483f075e8ad876 Mon Sep 17 00:00:00 2001 From: "FAREAST\\jiacfan" Date: Tue, 25 Aug 2020 14:32:24 +0800 Subject: [PATCH 10/10] Remove it.only. --- sdk/storage/storage-file-share/test/utils.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/storage/storage-file-share/test/utils.spec.ts b/sdk/storage/storage-file-share/test/utils.spec.ts index 3b710ec7794b..bc3b0335e9b3 100644 --- a/sdk/storage/storage-file-share/test/utils.spec.ts +++ b/sdk/storage/storage-file-share/test/utils.spec.ts @@ -40,11 +40,11 @@ describe("Utility Helpers", () => { ); } - beforeEach(async function() { + beforeEach(async function () { recorder = record(this, recorderEnvSetup); }); - afterEach(async function() { + afterEach(async function () { await recorder.stop(); }); @@ -98,7 +98,7 @@ describe("Utility Helpers", () => { ); }); - it.only("extractConnectionStringParts parses sas connection string with custom domain", async () => { + it("extractConnectionStringParts parses sas connection string with custom domain", async () => { const sasConnectionString = `FileEndpoint=${customDomainFileEndpoint}; SharedAccessSignature=${sharedAccessSignature}`; const connectionStringParts = extractConnectionStringParts(sasConnectionString); @@ -119,7 +119,7 @@ describe("Utility Helpers", () => { ); }); - it.only("isIpEndpointStyle", async () => { + it("isIpEndpointStyle", async () => { assert.equal( isIpEndpointStyle( URLBuilder.parse("https://192.0.0.10:1900/accountName/containerName/blobName")