From a2120d1c6ba00ce7061f38572b6ed9c2e95adefa Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 12 Mar 2013 16:12:38 -0100 Subject: [PATCH] Web.Routing - improve domains management --- .../Routing/SiteDomainHelperTests.cs | 8 +-- src/Umbraco.Web/Routing/AliasUrlProvider.cs | 4 +- src/Umbraco.Web/Routing/DomainHelper.cs | 5 +- src/Umbraco.Web/Routing/ISiteDomainHelper.cs | 3 +- src/Umbraco.Web/Routing/SiteDomainHelper.cs | 71 +++++++++++-------- 5 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Tests/Routing/SiteDomainHelperTests.cs b/src/Umbraco.Tests/Routing/SiteDomainHelperTests.cs index 6c5e4cfb3b..9a046925ef 100644 --- a/src/Umbraco.Tests/Routing/SiteDomainHelperTests.cs +++ b/src/Umbraco.Tests/Routing/SiteDomainHelperTests.cs @@ -236,7 +236,7 @@ namespace Umbraco.Tests.Routing new DomainAndUri(new MockDomain("domain3.com"), Uri.UriSchemeHttp), // no: not same site new DomainAndUri(new MockDomain("domain4.com"), Uri.UriSchemeHttp), // no: not same site new DomainAndUri(new MockDomain("domain1.org"), Uri.UriSchemeHttp), // yes: same site (though bogus setup) - }).ToArray(); + }, true).ToArray(); Assert.AreEqual(1, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); @@ -251,7 +251,7 @@ namespace Umbraco.Tests.Routing new DomainAndUri(new MockDomain("domain3.com"), Uri.UriSchemeHttp), // no: not same site new DomainAndUri(new MockDomain("domain4.com"), Uri.UriSchemeHttp), // no: not same site new DomainAndUri(new MockDomain("domain1.org"), Uri.UriSchemeHttp), // yes: same site (though bogus setup) - }).ToArray(); + }, true).ToArray(); Assert.AreEqual(1, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); @@ -270,7 +270,7 @@ namespace Umbraco.Tests.Routing new DomainAndUri(new MockDomain("domain3.org"), Uri.UriSchemeHttp), // yes: bound site new DomainAndUri(new MockDomain("domain4.com"), Uri.UriSchemeHttp), // no: not same site new DomainAndUri(new MockDomain("domain1.org"), Uri.UriSchemeHttp), // yes: same site (though bogus setup) - }).ToArray(); + }, true).ToArray(); Assert.AreEqual(3, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); @@ -288,7 +288,7 @@ namespace Umbraco.Tests.Routing new DomainAndUri(new MockDomain("domain3.org"), Uri.UriSchemeHttp), // yes: bound site new DomainAndUri(new MockDomain("domain4.com"), Uri.UriSchemeHttp), // no: not same site new DomainAndUri(new MockDomain("domain1.org"), Uri.UriSchemeHttp), // yes: same site (though bogus setup) - }).ToArray(); + }, true).ToArray(); Assert.AreEqual(3, output.Count()); Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray()); diff --git a/src/Umbraco.Web/Routing/AliasUrlProvider.cs b/src/Umbraco.Web/Routing/AliasUrlProvider.cs index 7aeb129948..6821e3c1fc 100644 --- a/src/Umbraco.Web/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Web/Routing/AliasUrlProvider.cs @@ -64,12 +64,12 @@ namespace Umbraco.Web.Routing return Enumerable.Empty(); var n = node; - var domainUris = DomainHelper.DomainsForNode(n.Id, current); + var domainUris = DomainHelper.DomainsForNode(n.Id, current, false); while (domainUris == null && n != null) // n is null at root { // move to parent node n = n.Parent; - domainUris = n == null ? null : DomainHelper.DomainsForNode(n.Id, current); + domainUris = n == null ? null : DomainHelper.DomainsForNode(n.Id, current, false); } var path = "/" + umbracoUrlName; diff --git a/src/Umbraco.Web/Routing/DomainHelper.cs b/src/Umbraco.Web/Routing/DomainHelper.cs index 191f4153ea..ccb1cfc159 100644 --- a/src/Umbraco.Web/Routing/DomainHelper.cs +++ b/src/Umbraco.Web/Routing/DomainHelper.cs @@ -77,10 +77,11 @@ namespace Umbraco.Web.Routing /// /// The node identifier. /// The uri, or null. + /// A value indicating whether to exclude the current/default domain. True by default. /// The domains and their uris, that match the specified uri, else null. /// If at least a domain is set on the node then the method returns the domains that /// best match the specified uri, else it returns null. - internal static IEnumerable DomainsForNode(int nodeId, Uri current) + internal static IEnumerable DomainsForNode(int nodeId, Uri current, bool excludeDefault = true) { // be safe if (nodeId <= 0) @@ -98,7 +99,7 @@ namespace Umbraco.Web.Routing // filter var helper = SiteDomainHelperResolver.Current.Helper; - return helper.MapDomains(current, domainAndUris).ToArray(); + return helper.MapDomains(current, domainAndUris, excludeDefault).ToArray(); } #endregion diff --git a/src/Umbraco.Web/Routing/ISiteDomainHelper.cs b/src/Umbraco.Web/Routing/ISiteDomainHelper.cs index 3f4cb3589f..b290c9b1c1 100644 --- a/src/Umbraco.Web/Routing/ISiteDomainHelper.cs +++ b/src/Umbraco.Web/Routing/ISiteDomainHelper.cs @@ -29,8 +29,9 @@ namespace Umbraco.Web.Routing /// /// The Uri of the current request. /// The list of DomainAndUri to filter. + /// A value indicating whether to exclude the current/default domain. /// The selected DomainAndUri items. /// The filter must return something, even empty, else an exception will be thrown. - IEnumerable MapDomains(Uri current, DomainAndUri[] domainAndUris); + IEnumerable MapDomains(Uri current, DomainAndUri[] domainAndUris, bool excludeDefault); } } diff --git a/src/Umbraco.Web/Routing/SiteDomainHelper.cs b/src/Umbraco.Web/Routing/SiteDomainHelper.cs index 69c3a59bfb..ea035fa061 100644 --- a/src/Umbraco.Web/Routing/SiteDomainHelper.cs +++ b/src/Umbraco.Web/Routing/SiteDomainHelper.cs @@ -194,36 +194,41 @@ namespace Umbraco.Web.Routing return MapDomain(domainAndUris, qualifiedSites, currentAuthority); } - /// - /// Filters a list of DomainAndUri to pick those that best matches the current request. - /// - /// The Uri of the current request. - /// The list of DomainAndUri to filter. - /// The selected DomainAndUri items. - /// The filter must return something, even empty, else an exception will be thrown. - public virtual IEnumerable MapDomains(Uri current, DomainAndUri[] domainAndUris) + /// + /// Filters a list of DomainAndUri to pick those that best matches the current request. + /// + /// The Uri of the current request. + /// The list of DomainAndUri to filter. + /// A value indicating whether to exclude the current/default domain. + /// The selected DomainAndUri items. + /// The filter must return something, even empty, else an exception will be thrown. + public virtual IEnumerable MapDomains(Uri current, DomainAndUri[] domainAndUris, bool excludeDefault) { var currentAuthority = current.GetLeftPart(UriPartial.Authority); - KeyValuePair[] candidateSites; - IEnumerable ret; + KeyValuePair[] candidateSites = null; + IEnumerable ret = domainAndUris; using (ConfigReadLock) // so nothing changes between GetQualifiedSites and access to bindings { var qualifiedSites = GetQualifiedSitesInsideLock(current); - // exclude the current one (avoid producing the absolute equivalent of what GetUrl returns) - var hintWithSlash = current.EndPathWithSlash(); - var hinted = domainAndUris.FirstOrDefault(d => d.Uri.EndPathWithSlash().IsBaseOf(hintWithSlash)); - ret = hinted == null ? domainAndUris : domainAndUris.Where(d => d != hinted); - - // exclude the default one (avoid producing a possible duplicate of what GetUrl returns) - // only if the default one cannot be the current one ie if hinted is not null - if (hinted == null && domainAndUris.Any()) + if (excludeDefault) { - // it is illegal to call MapDomain if domainAndUris is empty - // also, domainAndUris should NOT contain current, hence the test on hinted - var mainDomain = MapDomain(domainAndUris, qualifiedSites, currentAuthority); // what GetUrl would get - ret = ret.Where(d => d != mainDomain); + // exclude the current one (avoid producing the absolute equivalent of what GetUrl returns) + var hintWithSlash = current.EndPathWithSlash(); + var hinted = domainAndUris.FirstOrDefault(d => d.Uri.EndPathWithSlash().IsBaseOf(hintWithSlash)); + if (hinted != null) + ret = ret.Where(d => d != hinted); + + // exclude the default one (avoid producing a possible duplicate of what GetUrl returns) + // only if the default one cannot be the current one ie if hinted is not null + if (hinted == null && domainAndUris.Any()) + { + // it is illegal to call MapDomain if domainAndUris is empty + // also, domainAndUris should NOT contain current, hence the test on hinted + var mainDomain = MapDomain(domainAndUris, qualifiedSites, currentAuthority); // what GetUrl would get + ret = ret.Where(d => d != mainDomain); + } } // we do our best, but can't do the impossible @@ -236,17 +241,21 @@ namespace Umbraco.Web.Routing // if current belongs to a site, pick every element from domainAndUris that also belong // to that site -- or to any site bound to that site - candidateSites = new[] { currentSite }; - if (_bindings != null && _bindings.ContainsKey(currentSite.Key)) - { - var boundSites = qualifiedSites.Where(site => _bindings[currentSite.Key].Contains(site.Key)); - candidateSites = candidateSites.Union(boundSites).ToArray(); + if (!currentSite.Equals(default(KeyValuePair))) + { + candidateSites = new[] { currentSite }; + if (_bindings != null && _bindings.ContainsKey(currentSite.Key)) + { + var boundSites = qualifiedSites.Where(site => _bindings[currentSite.Key].Contains(site.Key)); + candidateSites = candidateSites.Union(boundSites).ToArray(); - // .ToArray ensures it is evaluated before the configuration lock is exited - } - } + // .ToArray ensures it is evaluated before the configuration lock is exited + } + } + } - return ret.Where(d => + // if we are able to filter, then filter, else return the whole lot + return candidateSites == null ? ret : ret.Where(d => { var authority = d.Uri.GetLeftPart(UriPartial.Authority); return candidateSites.Any(site => site.Value.Contains(authority));