Web.Routing - hide new wildcard domains from public APIs

only way to get them is through internal methods
+ improve / fix domains handling
+ fix failing tests
This commit is contained in:
Stephan
2013-03-12 15:16:12 -01:00
parent ca9f53738b
commit fc3f9dfeae
11 changed files with 85 additions and 60 deletions

View File

@@ -25,7 +25,7 @@ namespace Umbraco.Tests.Routing
void InitializeLanguagesAndDomains()
{
var domains = Domain.GetDomains();
var domains = Domain.GetDomains(true); // we want wildcards too here
foreach (var d in domains)
d.Delete();

View File

@@ -26,6 +26,10 @@ namespace Umbraco.Tests.Routing
true);
SettingsForTests.SettingsFilePath = Core.IO.IOHelper.MapPath(Core.IO.SystemDirectories.Config + Path.DirectorySeparatorChar, false);
SiteDomainHelperResolver.Reset();
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
FreezeResolution();
}
internal override IRoutesCache GetRoutesCache()

View File

@@ -20,6 +20,10 @@ namespace Umbraco.Tests.Routing
// ensure we can create them although the content is not in the database
TestHelper.DropForeignKeys("umbracoDomains");
SiteDomainHelperResolver.Reset();
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
FreezeResolution();
}
internal override IRoutesCache GetRoutesCache()
@@ -370,7 +374,7 @@ namespace Umbraco.Tests.Routing
[Test]
public void Get_Nice_Url_Alternate()
{
var routingContext = GetRoutingContext("http://domain1.com/test", 1111);
var routingContext = GetRoutingContext("http://domain1.com/en/test", 1111);
SettingsForTests.UseDirectoryUrls = true;
SettingsForTests.HideTopLevelNodeFromPath = false;
@@ -378,13 +382,12 @@ namespace Umbraco.Tests.Routing
InitializeLanguagesAndDomains();
SetDomains5();
var result = routingContext.UrlProvider.GetOtherUrls(100111);
var url = routingContext.UrlProvider.GetUrl(100111, true);
Assert.AreEqual("http://domain1.com/en/1001-1-1/", url);
var result = routingContext.UrlProvider.GetOtherUrls(100111).ToArray();
// will always get absolute urls
// all of them
// including the local one - duplicate?! - then must manually exclude?
Assert.AreEqual(3, result.Count());
Assert.IsTrue(result.Contains("http://domain1.com/en/1001-1-1/"));
Assert.AreEqual(2, result.Count());
Assert.IsTrue(result.Contains("http://domain1a.com/en/1001-1-1/"));
Assert.IsTrue(result.Contains("http://domain1b.com/en/1001-1-1/"));
}

View File

@@ -69,6 +69,10 @@ namespace Umbraco.Tests.Routing
// ensure we can create them although the content is not in the database
TestHelper.DropForeignKeys("umbracoDomains");
SiteDomainHelperResolver.Reset();
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
FreezeResolution();
}
internal override IRoutesCache GetRoutesCache()

View File

@@ -95,7 +95,7 @@ namespace Umbraco.Web.Routing
LogHelper.Debug<ContentFinderByNiceUrl>("Query matches, id={0}", () => docreq.PublishedContent.Id);
var rootNodeId = docreq.Domain == null ? (int?) null : docreq.Domain.RootNodeId;
var iscanon = _doDomainLookup && !DomainHelper.ExistsDomainInPath(DomainHelper.GetAllDomains(), node.Path, rootNodeId);
var iscanon = _doDomainLookup && !DomainHelper.ExistsDomainInPath(DomainHelper.GetAllDomains(false), node.Path, rootNodeId);
if (!iscanon)
LogHelper.Debug<ContentFinderByNiceUrl>("Non canonical url");

View File

@@ -17,22 +17,24 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Gets all domains defined in the system.
/// </summary>
/// <param name="includeWildcards">A value indicating whether to include wildcard domains.</param>
/// <returns>All domains defined in the system.</returns>
/// <remarks>This is to temporarily abstract Umbraco's API.</remarks>
internal static Domain[] GetAllDomains()
internal static Domain[] GetAllDomains(bool includeWildcards)
{
return Domain.GetDomains().ToArray();
return Domain.GetDomains(includeWildcards).ToArray();
}
/// <summary>
/// Gets all domains defined in the system at a specified node.
/// </summary>
/// <param name="nodeId">The node identifier.</param>
/// <param name="includeWildcards">A value indicating whether to include wildcard domains.</param>
/// <returns>All domains defined in the system at the specified node.</returns>
/// <remarks>This is to temporarily abstract Umbraco's API.</remarks>
internal static Domain[] GetNodeDomains(int nodeId)
internal static Domain[] GetNodeDomains(int nodeId, bool includeWildcards)
{
return Domain.GetDomainsById(nodeId);
return Domain.GetDomains(includeWildcards).Where(d => d.RootNodeId == nodeId).ToArray();
}
#endregion
@@ -44,7 +46,9 @@ namespace Umbraco.Web.Routing
/// </summary>
/// <param name="nodeId">The node identifier.</param>
/// <param name="current">The uri, or null.</param>
/// <returns>The domain and its uri, if any, that best matches the specified uri.</returns>
/// <returns>The domain and its uri, if any, that best matches the specified uri, else null.</returns>
/// <remarks>If at least a domain is set on the node then the method returns the domain that
/// best matches the specified uri, else it returns null.</remarks>
internal static DomainAndUri DomainForNode(int nodeId, Uri current)
{
// be safe
@@ -52,13 +56,19 @@ namespace Umbraco.Web.Routing
return null;
// get the domains on that node
var domains = GetNodeDomains(nodeId);
var domains = GetNodeDomains(nodeId, false);
// filter those that match
// none?
if (!domains.Any())
return null;
// else filter
var helper = SiteDomainHelperResolver.Current.Helper;
var domainAndUri = DomainForUri(domains, current, domainAndUris => helper.MapDomain(current, domainAndUris));
// return null or the uri
if (domainAndUri == null)
throw new Exception("DomainForUri returned null.");
return domainAndUri;
}
@@ -67,7 +77,9 @@ namespace Umbraco.Web.Routing
/// </summary>
/// <param name="nodeId">The node identifier.</param>
/// <param name="current">The uri, or null.</param>
/// <returns>The domains and their uris, that match the specified uri.</returns>
/// <returns>The domains and their uris, that match the specified uri, else null.</returns>
/// <remarks>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.</remarks>
internal static IEnumerable<DomainAndUri> DomainsForNode(int nodeId, Uri current)
{
// be safe
@@ -75,15 +87,18 @@ namespace Umbraco.Web.Routing
return null;
// get the domains on that node
var domains = GetNodeDomains(nodeId);
var domains = GetNodeDomains(nodeId, false);
// filter those that match
// none?
if (!domains.Any())
return null;
// get the domains and their uris
var domainAndUris = DomainsForUri(domains, current).ToArray();
// return null or a (maybe empty) enumerable of uris
// filter
var helper = SiteDomainHelperResolver.Current.Helper;
var domainAndUris2 = helper.MapDomains(current, domainAndUris).ToArray();
return domainAndUris2.Any() ? domainAndUris2 : null;
return helper.MapDomains(current, domainAndUris).ToArray();
}
#endregion
@@ -121,17 +136,16 @@ namespace Umbraco.Web.Routing
DomainAndUri domainAndUri;
if (current == null)
{
// take the first one by default (is that OK?)
domainAndUri = domainsAndUris.First();
// take the first one by default (what else can we do?)
domainAndUri = domainsAndUris.First(); // .First() protected by .Any() above
}
else
{
// look for a domain that would be the base of the hint
// assume only one can match the hint (is that OK?)
// 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 sort them out
// if none matches, then try to run the filter to pick a domain
if (domainAndUri == null && filter != null)
{
domainAndUri = filter(domainsAndUris);

View File

@@ -166,7 +166,7 @@ namespace Umbraco.Web.Routing
LogHelper.Debug<PublishedContentRequestEngine>("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri);
// try to find a domain matching the current request
var domainAndUri = DomainHelper.DomainForUri(Domain.GetDomains().ToArray(), _pcr.Uri);
var domainAndUri = DomainHelper.DomainForUri(DomainHelper.GetAllDomains(false), _pcr.Uri);
// handle domain
if (domainAndUri != null)
@@ -216,7 +216,7 @@ namespace Umbraco.Web.Routing
var nodePath = _pcr.PublishedContent.Path;
LogHelper.Debug<PublishedContentRequestEngine>("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath);
var rootNodeId = _pcr.HasDomain ? _pcr.Domain.RootNodeId : (int?)null;
var domain = DomainHelper.FindWildcardDomainInPath(Domain.GetDomains().ToArray(), nodePath, rootNodeId);
var domain = DomainHelper.FindWildcardDomainInPath(DomainHelper.GetAllDomains(true), nodePath, rootNodeId);
if (domain != null)
{

View File

@@ -208,15 +208,23 @@ namespace Umbraco.Web.Routing
IEnumerable<DomainAndUri> ret;
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)
ret = domainAndUris.Where(d => d.Uri.GetLeftPart(UriPartial.Authority) != currentAuthority);
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)
var mainDomain = MapDomain(domainAndUris, qualifiedSites, currentAuthority); // what GetUrl would get
ret = ret.Where(d => d != mainDomain);
// 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
if (qualifiedSites == null)
@@ -280,6 +288,11 @@ namespace Umbraco.Web.Routing
private static DomainAndUri MapDomain(DomainAndUri[] domainAndUris, Dictionary<string, string[]> qualifiedSites, string currentAuthority)
{
if (domainAndUris == null)
throw new ArgumentNullException("domainAndUris");
if (!domainAndUris.Any())
throw new ArgumentException("Cannot be empty.", "domainAndUris");
// we do our best, but can't do the impossible
if (qualifiedSites == null)
return domainAndUris.First();

View File

@@ -17,29 +17,6 @@ namespace Umbraco.Web.WebServices
/// <remarks>Nothing to do with Active Directory.</remarks>
public class DomainsApiController : UmbracoAuthorizedApiController
{
[HttpGet]
public DomainModel[] ListDomains(int nodeId)
{
var node = ApplicationContext.Current.Services.ContentService.GetById(nodeId);
if (node == null)
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(string.Format("There is no content node with id {0}.", nodeId)),
ReasonPhrase = "Node Not Found."
});
if (!UmbracoUser.GetPermissions(node.Path).Contains(global::umbraco.BusinessLogic.Actions.ActionAssignDomain.Instance.Letter))
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("You do not have permission to assign domains on that node."),
ReasonPhrase = "Permission Denied."
});
var domains = Routing.DomainHelper.GetNodeDomains(nodeId);
return domains.Select(d => new DomainModel(d.Name, d.Language.id)).ToArray();
}
[HttpPost]
// can't pass multiple complex args in json post request...
public PostBackModel SaveLanguageAndDomains(PostBackModel model)
@@ -61,7 +38,7 @@ namespace Umbraco.Web.WebServices
});
model.Valid = true;
var domains = Routing.DomainHelper.GetNodeDomains(model.NodeId);
var domains = Routing.DomainHelper.GetNodeDomains(model.NodeId, true);
var languages = global::umbraco.cms.businesslogic.language.Language.GetAllAsList().ToArray();
var language = model.Language > 0 ? languages.FirstOrDefault(l => l.id == model.Language) : null;

View File

@@ -43,7 +43,7 @@ namespace umbraco.dialogs
pane_domains.Text = ui.Text("assignDomain", "setDomains");
prop_language.Text = ui.Text("assignDomain", "language");
var nodeDomains = DomainHelper.GetNodeDomains(nodeId);
var nodeDomains = DomainHelper.GetNodeDomains(nodeId, true);
var wildcard = nodeDomains.FirstOrDefault(d => d.IsWildcard);
var sb = new StringBuilder();

View File

@@ -147,7 +147,12 @@ namespace umbraco.cms.businesslogic.web
internal static List<Domain> GetDomains()
{
return Cache.GetCacheItem<List<Domain>>("UmbracoDomainList", getDomainsSyncLock, TimeSpan.FromMinutes(30),
return GetDomains(false);
}
internal static List<Domain> GetDomains(bool includeWildcards)
{
var domains = Cache.GetCacheItem<List<Domain>>("UmbracoDomainList", getDomainsSyncLock, TimeSpan.FromMinutes(30),
delegate
{
List<Domain> result = new List<Domain>();
@@ -170,6 +175,11 @@ namespace umbraco.cms.businesslogic.web
}
return result;
});
if (!includeWildcards)
domains = domains.Where(d => !d.IsWildcard).ToList();
return domains;
}
public static Domain GetDomain(string DomainName)