/// <summary> /// Gets the domains that match a specified uri, into a group of domains. /// </summary> /// <param name="domains">The group of domains.</param> /// <param name="current">The uri, or null.</param> /// <returns>The domains and their normalized uris, that match the specified uri.</returns> internal static IEnumerable<DomainAndUri> DomainsForUri(Domain[] domains, Uri current) { var scheme = current == null ? Uri.UriSchemeHttp : current.Scheme; return domains .Where(d => !d.IsWildcard) .Select(SanitizeForBackwardCompatibility) .Select(d => new DomainAndUri(d, scheme)) .OrderByDescending(d => d.Uri.ToString()); }
/// <summary> /// Finds the domain that best matches a specified uri, into a group of domains. /// </summary> /// <param name="domains">The group of domains.</param> /// <param name="current">The uri, or null.</param> /// <param name="filter">A function to filter the list of domains, if more than one applies, or <c>null</c>.</param> /// <returns>The domain and its normalized uri, that best matches the specified uri.</returns> /// <remarks> /// <para>If more than one domain matches, then the <paramref name="filter"/> function is used to pick /// the right one, unless it is <c>null</c>, in which case the method returns <c>null</c>.</para> /// <para>The filter, if any, will be called only with a non-empty argument, and _must_ return something.</para> /// </remarks> internal static DomainAndUri DomainForUri(Domain[] domains, Uri current, Func<DomainAndUri[], DomainAndUri> filter = null) { // sanitize the list to have proper uris for comparison (scheme, path end with /) // we need to end with / because example.com/foo cannot match example.com/foobar // we need to order so example.com/foo matches before example.com/ var scheme = current == null ? Uri.UriSchemeHttp : current.Scheme; var domainsAndUris = domains .Where(d => !d.IsWildcard) .Select(SanitizeForBackwardCompatibility) .Select(d => new DomainAndUri(d, scheme)) .OrderByDescending(d => d.Uri.ToString()) .ToArray(); if (!domainsAndUris.Any()) return null; DomainAndUri domainAndUri; if (current == null) { // take the first one by default (what else can we do?) domainAndUri = domainsAndUris.First(); // .First() protected by .Any() above } else { // look for the first domain that would be the base of the hint var hintWithSlash = current.EndPathWithSlash(); domainAndUri = domainsAndUris .FirstOrDefault(d => d.Uri.EndPathWithSlash().IsBaseOf(hintWithSlash)); // if none matches, then try to run the filter to pick a domain if (domainAndUri == null && filter != null) { domainAndUri = filter(domainsAndUris); // if still nothing, pick the first one? // no: move that constraint to the filter, but check if (domainAndUri == null) throw new InvalidOperationException("The filter returned null."); } } return domainAndUri; }