< Summary - SonghayCore

Information
Class: Songhay.Extensions.UriExtensions
Assembly: SonghayCore
File(s): /home/rasx/sourceRoot/SonghayCore/SonghayCore/Extensions/UriExtensions.cs
Line coverage
2%
Covered lines: 1
Uncovered lines: 45
Coverable lines: 46
Total lines: 150
Line coverage: 2.1%
Branch coverage
5%
Covered branches: 1
Total branches: 18
Branch coverage: 5.5%
Method coverage

Method coverage is only available for sponsors.

Upgrade to PRO version

Metrics

File(s)

/home/rasx/sourceRoot/SonghayCore/SonghayCore/Extensions/UriExtensions.cs

#LineLine coverage
 1using System.Web;
 2
 3namespace Songhay.Extensions;
 4
 5/// <summary>
 6/// Extensions of <see cref="Uri"/>
 7/// </summary>
 8public static class UriExtensions
 9{
 10    /// <summary>
 11    /// Determines whether the <see cref="Uri" /> is a file.
 12    /// </summary>
 13    /// <param name="input">The input.</param>
 14    /// <remarks>
 15    /// Recall that <see cref="Uri.IsFile" /> is another way
 16    /// of stating that <c>Uri.Schema == Uri.UriSchemeFile</c>
 17    /// and that <see cref="System.IO"/> members can process URIs.
 18    ///
 19    /// Also note that the only way to truly define a directory
 20    /// or folder is with a trailing forward/back slash.
 21    /// </remarks>
 22    public static bool IsProbablyAFile(this Uri? input) =>
 023        input != null && (input.IsFile || Path.HasExtension(input.OriginalString));
 24
 25    /// <summary>
 26    /// This part of the signature string represents the storage account
 27    ///   targeted by the request. Will also include any additional query parameters/values.
 28    /// For ListContainers, this will return something like this:
 29    ///   /storageaccountname/\ncomp:list
 30    /// </summary>
 31    /// <param name="uri">The URI of the storage service.</param>
 32    /// <param name="accountName">The storage account name.</param>
 33    /// <returns><see cref="string" /> representing the canonicalized resource.</returns>
 34    /// <remarks>
 35    /// See https://github.com/Azure-Samples/storage-dotnet-rest-api-with-auth/tree/master
 36    ///
 37    /// See https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-requests-to-azure-storage
 38    ///
 39    /// See https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key
 40    ///
 41    /// See “Shared Key format for 2009-09-19 and later”
 42    /// [ https://docs.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key#shared-key-format-for-2009
 43    /// </remarks>
 44    public static string ToAzureStorageCanonicalizedResourceLocation(this Uri? uri, string? accountName)
 045    {
 046        ArgumentNullException.ThrowIfNull(uri);
 047        ArgumentNullException.ThrowIfNull(accountName);
 48
 49        // The absolute path is "/" because for we're getting a list of containers.
 050        StringBuilder sb = new StringBuilder("/").Append(accountName).Append(uri.AbsolutePath);
 51
 52        // Address.Query is the resource, such as "?comp=list".
 53        // This ends up with a NameValueCollection with 1 entry having key=comp, value=list.
 54        // It will have more entries if you have more query parameters.
 055        NameValueCollection values = HttpUtility.ParseQueryString(uri.Query);
 56
 057        foreach (var item in values.AllKeys
 058                     .Where(k => k != null)
 059                     .Select(k => k!.ToLowerInvariant()).OrderBy(k => k))
 060        {
 061            sb.Append('\n').Append(item).Append(':').Append(values[item]);
 062        }
 63
 064        return sb.ToString();
 065    }
 66
 67    /// <summary>
 68    /// Converts the <see cref="Uri" /> into a base URI.
 69    /// </summary>
 70    /// <param name="input">The input.</param>
 71    /// <returns>
 72    /// Returns a <see cref="string"/> like: <c>https://MyServer:8080/</c>
 73    /// </returns>
 74    public static string? ToBaseUri(this Uri? input)
 075    {
 076        if (input == null) return null;
 77
 078        var baseLocation = $"{input.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped)}/";
 79
 080        return baseLocation;
 081    }
 82
 83    /// <summary>
 84    /// Converts the <see cref="Uri" /> into its file name.
 85    /// </summary>
 86    /// <param name="input">The input.</param>
 287    public static string? ToFileName(this Uri? input) => Path.GetFileName(input?.LocalPath);
 88
 89    /// <summary>
 90    /// Converts the specified <see cref="Uri" />
 91    /// to its ‘expanded’ version.
 92    /// </summary>
 93    /// <param name="expandableUri">The expandable <see cref="Uri"/>.</param>
 94    /// <remarks>
 95    /// This member will call itself recursively
 96    /// until <see cref="HttpResponseMessageExtensions.IsMovedOrRedirected"/> returns <c>true</c>
 97    /// or <see cref="System.Net.Http.Headers.HttpResponseHeaders.Location"/> is null.
 98    /// </remarks>
 99    public static async Task<Uri?> ToExpandedUriAsync(this Uri? expandableUri)
 0100    {
 0101        ArgumentNullException.ThrowIfNull(expandableUri);
 102
 0103        var message = new HttpRequestMessage(HttpMethod.Get, expandableUri);
 104
 0105        using var response = await message.SendAsync();
 106
 0107        if (response.Headers.Location == null)
 0108        {
 0109            return message.RequestUri;
 110        }
 111
 0112        if (response.IsMovedOrRedirected())
 0113        {
 0114            return response.Headers.Location;
 115        }
 116
 0117        var uri = await response.Headers.Location
 0118            .ToExpandedUriAsync()
 0119            .ConfigureAwait(continueOnCapturedContext: false);
 120
 0121        return uri;
 0122    }
 123
 124    /// <summary>
 125    /// Converts the specified <see cref="Uri" />
 126    /// to its ‘expanded’ version.
 127    /// </summary>
 128    /// <param name="expandableUri">The expandable <see cref="Uri"/>.</param>
 129    public static async Task<KeyValuePair<Uri?, Uri?>> ToExpandedUriPairAsync(this Uri? expandableUri)
 0130    {
 0131        var expandedUri = await expandableUri
 0132            .ToExpandedUriAsync()
 0133            .ConfigureAwait(continueOnCapturedContext: false);
 134
 0135        return new KeyValuePair<Uri?, Uri?>(expandableUri, expandedUri);
 0136    }
 137
 138    /// <summary>
 139    /// Converts the <see cref="Uri"/> into a relative URI from query.
 140    /// </summary>
 141    /// <param name="input">The input.</param>
 142    public static Uri? ToRelativeUriFromQuery(this Uri? input)
 0143    {
 0144        if (input == null) return null;
 145
 0146        var query = input.OriginalString.Split('?').Last();
 147
 0148        return string.IsNullOrWhiteSpace(query) ? null : new Uri(query, UriKind.Relative);
 0149    }
 150}