< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 26
Coverable lines: 26
Total lines: 157
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
TryGetCredential(...)0%10100%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/Common/src/System/Net/CredentialCacheKey.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Globalization;
 9
 10namespace System.Net
 11{
 12    internal sealed class CredentialCacheKey : IEquatable<CredentialCacheKey?>
 13    {
 14        public readonly Uri UriPrefix;
 15        public readonly int UriPrefixLength = -1;
 16        public readonly string AuthenticationType;
 17
 18        internal CredentialCacheKey(Uri uriPrefix, string authenticationType)
 19        {
 20            Debug.Assert(uriPrefix != null);
 21            Debug.Assert(authenticationType != null);
 22
 23            UriPrefix = uriPrefix;
 24            UriPrefixLength = UriPrefix.AbsolutePath.LastIndexOf('/');
 25            AuthenticationType = authenticationType;
 26        }
 27
 28        internal bool Match(Uri uri, int prefixLen, string authenticationType)
 29        {
 30            if (uri == null || authenticationType == null)
 31            {
 32                return false;
 33            }
 34
 35            // If the protocols don't match, this credential is not applicable for the given Uri.
 36            if (!string.Equals(authenticationType, AuthenticationType, StringComparison.OrdinalIgnoreCase))
 37            {
 38                return false;
 39            }
 40
 41            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Match({UriPrefix} & {uri})");
 42
 43            return IsPrefix(uri, prefixLen);
 44        }
 45
 46        // IsPrefix (Uri)
 47        //
 48        // Determines whether <this> is a prefix of this URI. A prefix
 49        // match is defined as:
 50        //
 51        //     scheme match
 52        //     + host match
 53        //     + port match, if any
 54        //     + <prefix> path is a prefix of <URI> path, if any
 55        //
 56        // Returns:
 57        // True if <prefixUri> is a prefix of this URI
 58        private bool IsPrefix(Uri uri, int prefixLen)
 59        {
 60            Debug.Assert(uri != null);
 61            Uri uriPrefix = UriPrefix;
 62
 63            if (uriPrefix.Scheme != uri.Scheme || uriPrefix.Host != uri.Host || uriPrefix.Port != uri.Port)
 64            {
 65                return false;
 66            }
 67
 68            if (UriPrefixLength > prefixLen)
 69            {
 70                return false;
 71            }
 72
 73            // Compare the path prefix including the trailing '/' delimiter (UriPrefixLength points at
 74            // the last '/' in the prefix path). Including that delimiter ensures the prefix only matches
 75            // at a path-segment boundary, so a prefix such as "/admin/" does not incorrectly match a
 76            // sibling path like "/administrator/...".
 77            //
 78            // The path on the server may be case-sensitive, so the path portion is compared
 79            // case-sensitively (scheme, host, and port are already matched above).
 80            int compareLength = UriPrefixLength + 1;
 81            return uri.AbsolutePath.AsSpan(0, compareLength).Equals(uriPrefix.AbsolutePath.AsSpan(0, compareLength), Str
 82        }
 83
 84        public override int GetHashCode() =>
 85            StringComparer.OrdinalIgnoreCase.GetHashCode(AuthenticationType) ^
 86            UriPrefix.GetHashCode();
 87
 88        public bool Equals([NotNullWhen(true)] CredentialCacheKey? other)
 89        {
 90            if (other == null)
 91            {
 92                return false;
 93            }
 94
 95            bool equals =
 96                string.Equals(AuthenticationType, other.AuthenticationType, StringComparison.OrdinalIgnoreCase) &&
 97                UriPrefix.Equals(other.UriPrefix);
 98
 99            if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"Equals({this},{other}) returns {equals}");
 100
 101            return equals;
 102        }
 103
 104        public override bool Equals([NotNullWhen(true)] object? obj) => Equals(obj as CredentialCacheKey);
 105
 106        public override string ToString() =>
 107            string.Create(CultureInfo.InvariantCulture, $"[{UriPrefixLength}]:{UriPrefix}:{AuthenticationType}");
 108    }
 109
 110    internal static class CredentialCacheHelper
 111    {
 112        public static bool TryGetCredential(Dictionary<CredentialCacheKey, NetworkCredential> cache, Uri uriPrefix, stri
 0113        {
 0114            int longestMatchPrefix = -1;
 0115            mostSpecificMatch = null;
 0116            mostSpecificMatchUri = null;
 117
 0118            if (cache.Count == 0)
 0119            {
 0120                return false;
 121            }
 122
 123            // precompute the length of the prefix
 0124            int uriPrefixLength = uriPrefix.AbsolutePath.LastIndexOf('/');
 125
 126            // Enumerate through every credential in the cache, get match with longest prefix
 0127            foreach ((CredentialCacheKey key, NetworkCredential value) in cache)
 0128            {
 0129                int prefixLen = key.UriPrefixLength;
 130
 0131                if (prefixLen <= longestMatchPrefix)
 0132                {
 133                    // this credential can't provide a longer prefix match
 0134                    continue;
 135                }
 136
 137                // Determine if this credential is applicable to the current Uri/AuthType
 0138                if (key.Match(uriPrefix, uriPrefixLength, authType))
 0139                {
 140                    // update the information about currently preferred match
 0141                    longestMatchPrefix = prefixLen;
 0142                    mostSpecificMatch = value;
 0143                    mostSpecificMatchUri = key.UriPrefix;
 144
 0145                    if (uriPrefixLength == prefixLen)
 0146                    {
 147                        // we can't get any better than this
 0148                        break;
 149                    }
 0150                }
 0151            }
 152
 0153            return mostSpecificMatch != null;
 0154        }
 155    }
 156}
 157