< Summary

Class:Azure.Storage.Blobs.BlobUriBuilder
Assembly:Azure.Storage.Blobs
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlobUriBuilder.cs
Covered lines:93
Uncovered lines:4
Coverable lines:97
Total lines:352
Line coverage:95.8% (93 of 97)
Covered branches:48
Total branches:52
Branch coverage:92.3% (48 of 52)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
get_Scheme()-100%100%
set_Scheme(...)-100%100%
get_Host()-100%100%
set_Host(...)-100%100%
get_Port()-100%100%
set_Port(...)-100%100%
get_AccountName()-100%100%
set_AccountName(...)-100%100%
get_BlobContainerName()-100%100%
set_BlobContainerName(...)-100%100%
get_BlobName()-100%100%
set_BlobName(...)-100%100%
get_Snapshot()-100%100%
set_Snapshot(...)-100%100%
get_VersionId()-100%100%
set_VersionId(...)-100%100%
get_Sas()-100%100%
set_Sas(...)-100%100%
get_Query()-100%100%
set_Query(...)-100%100%
.ctor(...)-97.62%91.67%
ToUri()-100%100%
ToString()-0%100%
ResetUri()-100%100%
BuildUri()-93.1%92.31%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlobUriBuilder.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Linq;
 6using System.Net;
 7using System.Text;
 8using Azure.Core;
 9using Azure.Storage.Sas;
 10using Azure.Storage.Shared;
 11
 12namespace Azure.Storage.Blobs
 13{
 14    /// <summary>
 15    /// The <see cref="BlobUriBuilder"/> class provides a convenient way to
 16    /// modify the contents of a <see cref="System.Uri"/> instance to point to
 17    /// different Azure Storage resources like an account, container, or blob.
 18    ///
 19    /// For more information, see
 20    /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--a
 21    /// Naming and Referencing Containers, Blobs, and Metadata</see>.
 22    /// </summary>
 23    public class BlobUriBuilder
 24    {
 25        /// <summary>
 26        /// The Uri instance constructed by this builder.  It will be reset to
 27        /// null when changes are made and reconstructed when <see cref="Uri"/>
 28        /// is accessed.
 29        /// </summary>
 30        private Uri _uri;
 31
 32        /// <summary>
 33        /// Whether the Uri is a path-style Uri (i.e. it is an IP Uri or the domain includes a port that is used by the 
 34        /// </summary>
 35        private readonly bool _isPathStyleUri;
 36
 37        /// <summary>
 38        /// List of ports used for path style addressing.
 39        /// Copied from Microsoft.Azure.Storage.Core.Util
 40        /// </summary>
 641        private static readonly int[] PathStylePorts = { 10000, 10001, 10002, 10003, 10004, 10100, 10101, 10102, 10103, 
 42
 43        /// <summary>
 44        /// Gets or sets the scheme name of the URI.
 45        /// Example: "https"
 46        /// </summary>
 47        public string Scheme
 48        {
 666849            get => _scheme;
 2158850            set { ResetUri(); _scheme = value; }
 51        }
 52        private string _scheme;
 53
 54        /// <summary>
 55        /// Gets or sets the Domain Name System (DNS) host name or IP address
 56        /// of a server.
 57        ///
 58        /// Example: "account.blob.core.windows.net"
 59        /// </summary>
 60        public string Host
 61        {
 666862            get => _host;
 2158863            set { ResetUri(); _host = value; }
 64        }
 65        private string _host;
 66
 67        /// <summary>
 68        /// Gets or sets the port number of the URI.
 69        /// </summary>
 70        public int Port
 71        {
 666872            get => _port;
 2158873            set { ResetUri(); _port = value; }
 74        }
 75        private int _port;
 76
 77        /// <summary>
 78        /// Gets or sets the Azure Storage account name.
 79        /// </summary>
 80        public string AccountName
 81        {
 81282            get => _accountName;
 4317683            set { ResetUri(); _accountName = value; }
 84        }
 85        private string _accountName;
 86
 87        /// <summary>
 88        /// Gets or sets the name of a blob storage Container.  The value
 89        /// defaults to <see cref="String.Empty"/> if not present in the
 90        /// <see cref="System.Uri"/>.
 91        /// </summary>
 92        public string BlobContainerName
 93        {
 1379294            get => _containerName;
 4363295            set { ResetUri(); _containerName = value; }
 96        }
 97        private string _containerName;
 98
 99        /// <summary>
 100        /// Gets or sets the name of a blob.  The value defaults to
 101        /// <see cref="String.Empty"/> if not present in the <see cref="System.Uri"/>.
 102        /// </summary>
 103        public string BlobName
 104        {
 20132105            get => _blobName;
 42168106            set { ResetUri(); _blobName = value; }
 107        }
 108        private string _blobName;
 109
 110        /// <summary>
 111        /// Gets or sets the name of a blob snapshot.  The value defaults to
 112        /// <see cref="String.Empty"/> if not present in the <see cref="System.Uri"/>.
 113        /// </summary>
 114        public string Snapshot
 115        {
 14116116            get => _snapshot;
 22380117            set { ResetUri(); _snapshot = value; }
 118        }
 119        private string _snapshot;
 120
 121        /// <summary>
 122        /// Gets or sets the name of a blob version.  The value defaults to
 123        /// <see cref="string.Empty"/> if not present in the <see cref="System.Uri"/>.
 124        /// </summary>
 125        public string VersionId
 126        {
 6820127            get => _versionId;
 22056128            set { ResetUri(); _versionId = value; }
 129        }
 130        private string _versionId;
 131
 132        ///// <summary>
 133        ///// Gets or sets the VersionId.  The value defaults to
 134        ///// <see cref="String.Empty"/> if not present in the <see cref="Uri"/>.
 135        ///// </summary>
 136        //public string VersionId
 137        //{
 138        //    get => this._versionId;
 139        //    set { this.ResetUri(); this._versionId = value; }
 140        //}
 141        //private string _versionId;
 142
 143        /// <summary>
 144        /// Gets or sets the Shared Access Signature query parameters, or null
 145        /// if not present in the <see cref="System.Uri"/>.
 146        /// </summary>
 147        public BlobSasQueryParameters Sas
 148        {
 6760149            get => _sas;
 22128150            set { ResetUri(); _sas = value; }
 151        }
 152        private BlobSasQueryParameters _sas;
 153
 154        /// <summary>
 155        /// Gets or sets any query information included in the URI that's not
 156        /// relevant to addressing Azure storage resources.
 157        /// </summary>
 158        public string Query
 159        {
 6668160            get => _query;
 43176161            set { ResetUri(); _query = value; }
 162        }
 163        private string _query;
 164
 165        /// <summary>
 166        /// Initializes a new instance of the <see cref="BlobUriBuilder"/>
 167        /// class with the specified <see cref="System.Uri"/>.
 168        /// </summary>
 169        /// <param name="uri">
 170        /// The <see cref="System.Uri"/> to a storage resource.
 171        /// </param>
 7196172        public BlobUriBuilder(Uri uri)
 173        {
 7196174            uri = uri ?? throw new ArgumentNullException(nameof(uri));
 175
 7196176            Scheme = uri.Scheme;
 7196177            Host = uri.Host;
 7196178            Port = uri.Port;
 179
 7196180            AccountName = "";
 7196181            BlobContainerName = "";
 7196182            BlobName = "";
 183
 7196184            Snapshot = "";
 7196185            VersionId = "";
 7196186            Sas = null;
 7196187            Query = "";
 188
 189            // Find the account, container, & blob names (if any)
 7196190            if (!string.IsNullOrEmpty(uri.AbsolutePath))
 191            {
 7196192                var path = uri.GetPath();
 193
 7196194                var startIndex = 0;
 195
 7196196                _isPathStyleUri = uri.IsHostIPEndPointStyle() || PathStylePorts.Contains(uri.Port);
 7196197                if (_isPathStyleUri)
 198                {
 136199                    var accountEndIndex = path.IndexOf("/", StringComparison.InvariantCulture);
 200
 201                    // Slash not found; path has account name & no container name
 136202                    if (accountEndIndex == -1)
 203                    {
 76204                        AccountName = path;
 76205                        startIndex = path.Length;
 206                    }
 207                    else
 208                    {
 60209                        AccountName = path.Substring(0, accountEndIndex);
 60210                        startIndex = accountEndIndex + 1;
 211                    }
 212                }
 213                else
 214                {
 7060215                    AccountName = uri.GetAccountNameFromDomain(Constants.Blob.UriSubDomain) ?? string.Empty;
 216                }
 217
 218                // Find the next slash (if it exists)
 7196219                var containerEndIndex = path.IndexOf("/", startIndex, StringComparison.InvariantCulture);
 7196220                if (containerEndIndex == -1)
 221                {
 6448222                    BlobContainerName = path.Substring(startIndex); // Slash not found; path has container name & no blo
 223                }
 224                else
 225                {
 748226                    BlobContainerName = path.Substring(startIndex, containerEndIndex - startIndex); // The container nam
 748227                    BlobName = path.Substring(containerEndIndex + 1).UnescapePath();   // The blob name is after the con
 228                }
 229            }
 230
 231            // Convert the query parameters to a case-sensitive map & trim whitespace
 7196232            var paramsMap = new UriQueryParamsCollection(uri.Query);
 233
 7196234            if (paramsMap.TryGetValue(Constants.SnapshotParameterName, out var snapshotTime))
 235            {
 52236                Snapshot = snapshotTime;
 237
 238                // If we recognized the query parameter, remove it from the map
 52239                paramsMap.Remove(Constants.SnapshotParameterName);
 240            }
 241
 7196242            if (paramsMap.TryGetValue(Constants.VersionIdParameterName, out var versionId))
 243            {
 48244                VersionId = versionId;
 245
 246                // If we recognized the query parameter, remove it from the map
 48247                paramsMap.Remove(Constants.VersionIdParameterName);
 248            }
 249
 7196250            if (!string.IsNullOrEmpty(Snapshot) && !string.IsNullOrEmpty(VersionId))
 251            {
 0252                throw new ArgumentException("Snapshot and VersionId cannot both be set.");
 253            }
 254
 7196255            if (paramsMap.ContainsKey(Constants.Sas.Parameters.Version))
 256            {
 148257                Sas = new BlobSasQueryParameters(paramsMap);
 258            }
 259
 7196260            Query = paramsMap.ToString();
 7196261        }
 262
 263        /// <summary>
 264        /// Returns the <see cref="System.Uri"/> constructed from the
 265        /// <see cref="BlobUriBuilder"/>'s fields. The <see cref="Uri.Query"/>
 266        /// property contains the SAS and additional query parameters.
 267        /// </summary>
 268        public Uri ToUri()
 269        {
 6604270            if (_uri == null)
 271            {
 6604272                _uri = BuildUri().ToUri();
 273            }
 6604274            return _uri;
 275        }
 276
 277        /// <summary>
 278        /// Returns the display string for the specified
 279        /// <see cref="BlobUriBuilder"/> instance.
 280        /// </summary>
 281        /// <returns>
 282        /// The display string for the specified <see cref="BlobUriBuilder"/>
 283        /// instance.
 284        /// </returns>
 285        public override string ToString() =>
 0286            BuildUri().ToString();
 287
 288        /// <summary>
 289        /// Reset our cached URI.
 290        /// </summary>
 291        private void ResetUri() =>
 101160292            _uri = null;
 293
 294        /// <summary>
 295        /// Construct a <see cref="RequestUriBuilder"/> representing the
 296        /// <see cref="BlobUriBuilder"/>'s fields. The <see cref="Uri.Query"/>
 297        /// property contains the SAS, snapshot, and unparsed query parameters.
 298        /// </summary>
 299        /// <returns>The constructed <see cref="RequestUriBuilder"/>.</returns>
 300        private RequestUriBuilder BuildUri()
 301        {
 302            // Concatenate account, container, & blob names (if they exist)
 6604303            var path = new StringBuilder("");
 304            // only append the account name to the path for Ip style Uri.
 305            // regular style Uri will already have account name in domain
 6604306            if (_isPathStyleUri && !string.IsNullOrWhiteSpace(AccountName))
 307            {
 64308                path.Append("/").Append(AccountName);
 309            }
 6604310            if (!string.IsNullOrWhiteSpace(BlobContainerName))
 311            {
 6592312                path.Append("/").Append(BlobContainerName);
 6592313                if (BlobName != null && BlobName.Length > 0)
 314                {
 6516315                    path.Append("/").Append(Uri.EscapeDataString(BlobName));
 316                }
 317            }
 318
 319            // Concatenate query parameters
 6604320            var query = new StringBuilder(Query);
 6604321            if (!string.IsNullOrWhiteSpace(Snapshot))
 322            {
 240323                if (query.Length > 0)
 0324                { query.Append("&"); }
 240325                query.Append(Constants.SnapshotParameterName).Append("=").Append(Snapshot);
 326            }
 6604327            if (!string.IsNullOrWhiteSpace(VersionId))
 328            {
 136329                if (query.Length > 0)
 0330                { query.Append("&"); }
 136331                query.Append(Constants.VersionIdParameterName).Append("=").Append(VersionId);
 332            }
 6604333            var sas = Sas?.ToString();
 6604334            if (!string.IsNullOrWhiteSpace(sas))
 335            {
 148336                if (query.Length > 0)
 12337                { query.Append("&"); }
 148338                query.Append(sas);
 339            }
 340
 341            // Use RequestUriBuilder, which has slightly nicer formatting
 6604342            return new RequestUriBuilder
 6604343            {
 6604344                Scheme = Scheme,
 6604345                Host = Host,
 6604346                Port = Port,
 6604347                Path = path.ToString(),
 6604348                Query = query.Length > 0 ? "?" + query.ToString() : null
 6604349            };
 350        }
 351    }
 352}