Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 28 additions & 23 deletions sdk/storage/azblob/internal/shared/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,6 @@ func ParseConnectionString(connectionString string) (ParsedConnectionString, err
connStrMap[parts[0]] = parts[1]
}

accountName, ok := connStrMap["AccountName"]
if !ok {
return ParsedConnectionString{}, errors.New("connection string missing AccountName")
}

accountKey, ok := connStrMap["AccountKey"]
if !ok {
sharedAccessSignature, ok := connStrMap["SharedAccessSignature"]
if !ok {
return ParsedConnectionString{}, errors.New("connection string missing AccountKey and SharedAccessSignature")
}
return ParsedConnectionString{
ServiceURL: fmt.Sprintf("%v://%v.blob.%v/?%v", defaultScheme, accountName, defaultSuffix, sharedAccessSignature),
}, nil
}

protocol, ok := connStrMap["DefaultEndpointsProtocol"]
if !ok {
protocol = defaultScheme
Expand All @@ -113,19 +97,40 @@ func ParseConnectionString(connectionString string) (ParsedConnectionString, err
suffix = defaultSuffix
}

if blobEndpoint, ok := connStrMap["BlobEndpoint"]; ok {
blobEndpoint, has_blobEndpoint := connStrMap["BlobEndpoint"]
accountName, has_accountName := connStrMap["AccountName"]

var serviceURL string
if has_blobEndpoint {
serviceURL = blobEndpoint
} else if has_accountName {
serviceURL = fmt.Sprintf("%v://%v.blob.%v", protocol, accountName, suffix)
} else {
return ParsedConnectionString{}, errors.New("connection string needs either AccountName or BlobEndpoint")
}

if !strings.HasSuffix(serviceURL, "/") {
// add a trailing slash to be consistent with the portal
serviceURL += "/"
}

accountKey, has_accountKey := connStrMap["AccountKey"]
sharedAccessSignature, has_sharedAccessSignature := connStrMap["SharedAccessSignature"]

if has_accountName && has_accountKey {
return ParsedConnectionString{
ServiceURL: blobEndpoint,
ServiceURL: serviceURL,
AccountName: accountName,
AccountKey: accountKey,
}, nil
} else if has_sharedAccessSignature {
return ParsedConnectionString{
ServiceURL: fmt.Sprintf("%v?%v", serviceURL, sharedAccessSignature),
}, nil
} else {
return ParsedConnectionString{}, errors.New("connection string needs either AccountKey or SharedAccessSignature")
}

return ParsedConnectionString{
ServiceURL: fmt.Sprintf("%v://%v.blob.%v", protocol, accountName, suffix),
AccountName: accountName,
AccountKey: accountKey,
}, nil
}

// SerializeBlobTags converts tags to generated.BlobTags
Expand Down
59 changes: 52 additions & 7 deletions sdk/storage/azblob/internal/shared/shared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestParseConnectionString(t *testing.T) {
connStr := "DefaultEndpointsProtocol=https;AccountName=dummyaccount;AccountKey=secretkeykey;EndpointSuffix=core.windows.net"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.blob.core.windows.net", parsed.ServiceURL)
require.Equal(t, "https://dummyaccount.blob.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}
Expand All @@ -46,7 +46,16 @@ func TestParseConnectionStringHTTP(t *testing.T) {
connStr := "DefaultEndpointsProtocol=http;AccountName=dummyaccount;AccountKey=secretkeykey;EndpointSuffix=core.windows.net"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://dummyaccount.blob.core.windows.net", parsed.ServiceURL)
require.Equal(t, "http://dummyaccount.blob.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringSuffixTrailingSlash(t *testing.T) {
connStr := "DefaultEndpointsProtocol=https;AccountName=dummyaccount;AccountKey=secretkeykey;EndpointSuffix=core.windows.net/"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.blob.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}
Expand All @@ -55,7 +64,7 @@ func TestParseConnectionStringBasic(t *testing.T) {
connStr := "AccountName=dummyaccount;AccountKey=secretkeykey"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.blob.core.windows.net", parsed.ServiceURL)
require.Equal(t, "https://dummyaccount.blob.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}
Expand All @@ -64,7 +73,7 @@ func TestParseConnectionStringCustomDomain(t *testing.T) {
connStr := "AccountName=dummyaccount;AccountKey=secretkeykey;BlobEndpoint=www.mydomain.com;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "www.mydomain.com", parsed.ServiceURL)
require.Equal(t, "www.mydomain.com/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}
Expand All @@ -78,20 +87,56 @@ func TestParseConnectionStringSAS(t *testing.T) {
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASAndEndpointAndAccountName(t *testing.T) {
connStr := "AccountName=devstoreaccount1;SharedAccessSignature=fakesharedaccesssignature;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:10000/devstoreaccount1/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASSuffixTrailingSlash(t *testing.T) {
connStr := "AccountName=dummyaccount;SharedAccessSignature=fakesharedaccesssignature;EndpointSuffix=core.windows.net/"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.blob.core.windows.net/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASAndEndpoint(t *testing.T) {
connStr := "SharedAccessSignature=fakesharedaccesssignature;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:10000/devstoreaccount1/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASAndEndpointTrailingSlash(t *testing.T) {
connStr := "SharedAccessSignature=fakesharedaccesssignature;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1/;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:10000/devstoreaccount1/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringChinaCloud(t *testing.T) {
connStr := "AccountName=dummyaccountname;AccountKey=secretkeykey;DefaultEndpointsProtocol=http;EndpointSuffix=core.chinacloudapi.cn;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://dummyaccountname.blob.core.chinacloudapi.cn", parsed.ServiceURL)
require.Equal(t, "http://dummyaccountname.blob.core.chinacloudapi.cn/", parsed.ServiceURL)
require.Equal(t, "dummyaccountname", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestCParseConnectionStringAzurite(t *testing.T) {
func TestParseConnectionStringAzurite(t *testing.T) {
connStr := "DefaultEndpointsProtocol=http;AccountName=dummyaccountname;AccountKey=secretkeykey;BlobEndpoint=http://local-machine:11002/custom/account/path/faketokensignature;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://local-machine:11002/custom/account/path/faketokensignature", parsed.ServiceURL)
require.Equal(t, "http://local-machine:11002/custom/account/path/faketokensignature/", parsed.ServiceURL)
require.Equal(t, "dummyaccountname", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}
Expand Down
52 changes: 28 additions & 24 deletions sdk/storage/azqueue/internal/shared/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,22 +78,6 @@ func ParseConnectionString(connectionString string) (ParsedConnectionString, err
connStrMap[parts[0]] = parts[1]
}

accountName, ok := connStrMap["AccountName"]
if !ok {
return ParsedConnectionString{}, errors.New("connection string missing AccountName")
}

accountKey, ok := connStrMap["AccountKey"]
if !ok {
sharedAccessSignature, ok := connStrMap["SharedAccessSignature"]
if !ok {
return ParsedConnectionString{}, errors.New("connection string missing AccountKey and SharedAccessSignature")
}
return ParsedConnectionString{
ServiceURL: fmt.Sprintf("%v://%v.queue.%v/?%v", defaultScheme, accountName, defaultSuffix, sharedAccessSignature),
}, nil
}

protocol, ok := connStrMap["DefaultEndpointsProtocol"]
if !ok {
protocol = defaultScheme
Expand All @@ -104,19 +88,39 @@ func ParseConnectionString(connectionString string) (ParsedConnectionString, err
suffix = defaultSuffix
}

if queueEndpoint, ok := connStrMap["QueueEndpoint"]; ok {
queueEndpoint, has_queueEndpoint := connStrMap["QueueEndpoint"]
accountName, has_accountName := connStrMap["AccountName"]

var serviceURL string
if has_queueEndpoint {
serviceURL = queueEndpoint
} else if has_accountName {
serviceURL = fmt.Sprintf("%v://%v.queue.%v", protocol, accountName, suffix)
} else {
return ParsedConnectionString{}, errors.New("connection string needs either AccountName or QueueEndpoint")
}

if !strings.HasSuffix(serviceURL, "/") {
// add a trailing slash to be consistent with the portal
serviceURL += "/"
}

accountKey, has_accountKey := connStrMap["AccountKey"]
sharedAccessSignature, has_sharedAccessSignature := connStrMap["SharedAccessSignature"]

if has_accountName && has_accountKey {
return ParsedConnectionString{
ServiceURL: queueEndpoint,
ServiceURL: serviceURL,
AccountName: accountName,
AccountKey: accountKey,
}, nil
} else if has_sharedAccessSignature {
return ParsedConnectionString{
ServiceURL: fmt.Sprintf("%v?%v", serviceURL, sharedAccessSignature),
}, nil
} else {
return ParsedConnectionString{}, errors.New("connection string needs either AccountKey or SharedAccessSignature")
}

return ParsedConnectionString{
ServiceURL: fmt.Sprintf("%v://%v.queue.%v", protocol, accountName, suffix),
AccountName: accountName,
AccountKey: accountKey,
}, nil
}

func GetClientOptions[T any](o *T) *T {
Expand Down
141 changes: 141 additions & 0 deletions sdk/storage/azqueue/internal/shared/shared_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package shared

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestParseConnectionStringInvalid(t *testing.T) {
badConnectionStrings := []string{
"",
"foobar",
"foo;bar;baz",
"foo=;bar=;",
"=",
";",
"=;==",
"foobar=baz=foo",
}

for _, badConnStr := range badConnectionStrings {
parsed, err := ParseConnectionString(badConnStr)
require.Error(t, err)
require.Zero(t, parsed)
//require.Contains(t, err.Error(), errConnectionString.Error())
}
}

func TestParseConnectionString(t *testing.T) {
connStr := "DefaultEndpointsProtocol=https;AccountName=dummyaccount;AccountKey=secretkeykey;EndpointSuffix=core.windows.net"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.queue.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringHTTP(t *testing.T) {
connStr := "DefaultEndpointsProtocol=http;AccountName=dummyaccount;AccountKey=secretkeykey;EndpointSuffix=core.windows.net"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://dummyaccount.queue.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringSuffixTrailingSlash(t *testing.T) {
connStr := "DefaultEndpointsProtocol=https;AccountName=dummyaccount;AccountKey=secretkeykey;EndpointSuffix=core.windows.net/"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.queue.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringBasic(t *testing.T) {
connStr := "AccountName=dummyaccount;AccountKey=secretkeykey"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.queue.core.windows.net/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringCustomDomain(t *testing.T) {
connStr := "AccountName=dummyaccount;AccountKey=secretkeykey;QueueEndpoint=www.mydomain.com;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "www.mydomain.com/", parsed.ServiceURL)
require.Equal(t, "dummyaccount", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringSAS(t *testing.T) {
connStr := "AccountName=dummyaccount;SharedAccessSignature=fakesharedaccesssignature;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.queue.core.windows.net/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASAndEndpointAndCustomDomain(t *testing.T) {
connStr := "AccountName=devstoreaccount1;SharedAccessSignature=fakesharedaccesssignature;QueueEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:10000/devstoreaccount1/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASSuffixTrailingSlash(t *testing.T) {
connStr := "AccountName=dummyaccount;SharedAccessSignature=fakesharedaccesssignature;EndpointSuffix=core.windows.net/"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "https://dummyaccount.queue.core.windows.net/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASAndEndpoint(t *testing.T) {
connStr := "SharedAccessSignature=fakesharedaccesssignature;QueueEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:10000/devstoreaccount1/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringSASAndEndpointTrailingSlash(t *testing.T) {
connStr := "SharedAccessSignature=fakesharedaccesssignature;QueueEndpoint=http://127.0.0.1:10000/devstoreaccount1/;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:10000/devstoreaccount1/?fakesharedaccesssignature", parsed.ServiceURL)
require.Empty(t, parsed.AccountName)
require.Empty(t, parsed.AccountKey)
}

func TestParseConnectionStringChinaCloud(t *testing.T) {
connStr := "AccountName=dummyaccountname;AccountKey=secretkeykey;DefaultEndpointsProtocol=http;EndpointSuffix=core.chinacloudapi.cn;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://dummyaccountname.queue.core.chinacloudapi.cn/", parsed.ServiceURL)
require.Equal(t, "dummyaccountname", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}

func TestParseConnectionStringAzurite(t *testing.T) {
connStr := "DefaultEndpointsProtocol=http;AccountName=dummyaccountname;AccountKey=secretkeykey;QueueEndpoint=http://local-machine:11002/custom/account/path/faketokensignature;"
parsed, err := ParseConnectionString(connStr)
require.NoError(t, err)
require.Equal(t, "http://local-machine:11002/custom/account/path/faketokensignature/", parsed.ServiceURL)
require.Equal(t, "dummyaccountname", parsed.AccountName)
require.Equal(t, "secretkeykey", parsed.AccountKey)
}