< Summary

Class:Azure.Storage.UriExtensions
Assembly:Azure.Storage.Common
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Common\src\Shared\UriExtensions.cs
Covered lines:9
Uncovered lines:30
Coverable lines:39
Total lines:139
Line coverage:23% (9 of 39)
Covered branches:5
Total branches:28
Branch coverage:17.8% (5 of 28)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
AppendToPath(...)-0%0%
GetQueryParameters(...)-33.33%30%
GetAccountNameFromDomain(...)-0%100%
GetAccountNameFromDomain(...)-0%0%
GetPath(...)-0%0%
IsHostIPEndPointStyle(...)-0%0%
AppendQueryParameter(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Common\src\Shared\UriExtensions.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Globalization;
 7using System.Net;
 8using System.Text;
 9
 10namespace Azure.Storage
 11{
 12    /// <summary>
 13    /// Extension methods used to manipulate URIs.
 14    /// </summary>
 15    internal static class UriExtensions
 16    {
 17        /// <summary>
 18        /// Append a segment to a URIs path.
 19        /// </summary>
 20        /// <param name="uri">The URI.</param>
 21        /// <param name="segment">The relative segment to append.</param>
 22        /// <returns>The combined URI.</returns>
 23        public static Uri AppendToPath(this Uri uri, string segment)
 24        {
 025            var builder = new UriBuilder(uri);
 026            var path = builder.Path;
 027            var seperator = (path.Length == 0 || path[path.Length - 1] != '/') ? "/" : "";
 28            // In URLs, the percent sign is used to encode special characters, so if the segment
 29            // has a percent sign in their URL path, we have to encode it before adding it to the path
 030            segment = segment.Replace(Constants.PercentSign, Constants.EncodedPercentSign);
 031            builder.Path += seperator + segment;
 032            return builder.Uri;
 33        }
 34
 35        /// <summary>
 36        /// Get the (already encoded) query parameters on a URI.
 37        /// </summary>
 38        /// <param name="uri">The URI.</param>
 39        /// <returns>Dictionary mapping query parameters to values.</returns>
 40        public static IDictionary<string, string> GetQueryParameters(this Uri uri)
 41        {
 442            var parameters = new Dictionary<string, string>();
 443            var query = uri.Query ?? "";
 444            if (!string.IsNullOrEmpty(query))
 45            {
 046                if (query.StartsWith("?", true, CultureInfo.InvariantCulture))
 47                {
 048                    query = query.Substring(1);
 49                }
 050                foreach (var param in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
 51                {
 052                    var parts = param.Split(new[] { '=' }, 2);
 053                    var name = WebUtility.UrlDecode(parts[0]);
 054                    if (parts.Length == 1)
 55                    {
 056                        parameters.Add(name, default);
 57                    }
 58                    else
 59                    {
 060                        parameters.Add(name, WebUtility.UrlDecode(parts[1]));
 61                    }
 62                }
 63            }
 464            return parameters;
 65        }
 66
 67        /// <summary>
 68        /// Get the account name from the domain portion of a Uri.
 69        /// </summary>
 70        /// <param name="uri">The Uri.</param>
 71        /// <param name="serviceSubDomain">The service subdomain used to validate that the
 72        /// domain is in the expected format. This should be "blob" for blobs, "file" for files,
 73        /// "queue" for queues, "blob" and "dfs" for datalake.</param>
 74        /// <returns>Account name or null if not able to be parsed.</returns>
 75        public static string GetAccountNameFromDomain(this Uri uri, string serviceSubDomain) =>
 076            GetAccountNameFromDomain(uri.Host, serviceSubDomain);
 77
 78        /// <summary>
 79        /// Get the account name from the host.
 80        /// </summary>
 81        /// <param name="host">Host.</param>
 82        /// <param name="serviceSubDomain">The service subdomain used to validate that the
 83        /// domain is in the expected format. This should be "blob" for blobs, "file" for files,
 84        /// "queue" for queues, "blob" and "dfs" for datalake.</param>
 85        /// <returns>Account name or null if not able to be parsed.</returns>
 86        public static string GetAccountNameFromDomain(string host, string serviceSubDomain)
 87        {
 088            var accountEndIndex = host.IndexOf(".", StringComparison.InvariantCulture);
 089            if (accountEndIndex >= 0)
 90            {
 091                var serviceStartIndex = accountEndIndex + 1;
 092                var serviceEndIndex = host.IndexOf(".", serviceStartIndex, StringComparison.InvariantCulture);
 093                if (serviceEndIndex > serviceStartIndex)
 94                {
 095                    var service = host.Substring(serviceStartIndex, serviceEndIndex - serviceStartIndex);
 096                    if (service == serviceSubDomain)
 97                    {
 098                        return host.Substring(0, accountEndIndex);
 99                    }
 100                }
 101            }
 0102            return null;
 103        }
 104
 105        /// <summary>
 106        /// If path starts with a slash, remove it
 107        /// </summary>
 108        /// <param name="uri">The Uri.</param>
 109        /// <returns>Sanitized Uri.</returns>
 110        public static string GetPath(this Uri uri) =>
 0111            (uri.AbsolutePath[0] == '/') ?
 0112                uri.AbsolutePath.Substring(1) :
 0113                uri.AbsolutePath;
 114
 115        // See remarks at https://docs.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=netframework-4.
 116        /// <summary>
 117        /// Check to see if Uri is using IP Endpoint style.
 118        /// </summary>
 119        /// <param name="uri">The Uri.</param>
 120        /// <returns>True if using IP Endpoint style.</returns>
 121        public static bool IsHostIPEndPointStyle(this Uri uri) =>
 0122           !string.IsNullOrEmpty(uri.Host) &&
 0123            uri.Host.IndexOf(".", StringComparison.InvariantCulture) >= 0 &&
 0124            IPAddress.TryParse(uri.Host, out _);
 125
 126        /// <summary>
 127        /// Appends a query parameter to the string builder.
 128        /// </summary>
 129        /// <param name="sb">string builder instance.</param>
 130        /// <param name="key">query parameter key.</param>
 131        /// <param name="value">query parameter value.</param>
 132        internal static void AppendQueryParameter(this StringBuilder sb, string key, string value) =>
 1860133            sb
 1860134            .Append(sb.Length > 0 ? "&" : "")
 1860135            .Append(key)
 1860136            .Append('=')
 1860137            .Append(value);
 138    }
 139}