internal string GetUrlFromRoute(string route, UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode) { if (string.IsNullOrWhiteSpace(route)) { LogHelper.Debug <DefaultUrlProvider>( "Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.", () => id); return(null); } if (route.StartsWith("err/")) { LogHelper.Debug <DefaultUrlProvider>( "Page with nodeId={0} has a colliding url with page with nodeId={1}.", () => id, () => route.Substring(4)); return("#err-" + route.Substring(4)); } var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); // extract domainUri and path // route is /<path> or <domainRootId>/<path> var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); var domainUri = pos == 0 ? null : domainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current); // assemble the url from domainUri (maybe null) and path return(AssembleUrl(domainUri, path, current, mode).ToString()); }
/// <summary> /// Looks for wildcard domains in the path and updates <c>Culture</c> accordingly. /// </summary> internal void HandleWildcardDomains() { const string tracePrefix = "HandleWildcardDomains: "; if (_pcr.HasPublishedContent == false) { return; } var nodePath = _pcr.PublishedContent.Path; ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath); var rootNodeId = _pcr.HasDomain ? _pcr.UmbracoDomain.RootContentId : (int?)null; var domain = DomainHelper.FindWildcardDomainInPath(Services.DomainService.GetAll(true), nodePath, rootNodeId); if (domain != null && domain.LanguageIsoCode.IsNullOrWhiteSpace() == false) { _pcr.Culture = new CultureInfo(domain.LanguageIsoCode); ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}Got domain on node {1}, set culture to \"{2}\".", () => tracePrefix, () => domain.RootContentId, () => _pcr.Culture.Name); } else { ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}No match.", () => tracePrefix); } }
/// <summary> /// Looks for wildcard domains in the path and updates <c>Culture</c> accordingly. /// </summary> internal void HandleWildcardDomains(PublishedRequest request) { const string tracePrefix = "HandleWildcardDomains: "; if (request.HasPublishedContent == false) { return; } var nodePath = request.PublishedContent.Path; _logger.Debug <PublishedRouter>("{TracePrefix}Path={NodePath}", tracePrefix, nodePath); var rootNodeId = request.HasDomain ? request.Domain.ContentId : (int?)null; var domain = DomainHelper.FindWildcardDomainInPath(request.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), nodePath, rootNodeId); // always has a contentId and a culture if (domain != null) { request.Culture = domain.Culture; _logger.Debug <PublishedRouter>("{TracePrefix}Got domain on node {DomainContentId}, set culture to {CultureName}", tracePrefix, domain.ContentId, request.Culture.Name); } else { _logger.Debug <PublishedRouter>("{TracePrefix}No match.", tracePrefix); } }
/// <summary> /// Gets the other urls of a published content. /// </summary> /// <param name="umbracoContext">The Umbraco context.</param> /// <param name="id">The published content id.</param> /// <param name="current">The current absolute url.</param> /// <returns>The other urls for the published content.</returns> /// <remarks> /// <para>Other urls are those that <c>GetUrl</c> would not return in the current context, but would be valid /// urls for the node in other contexts (different domain for current request, umbracoUrlAlias...).</para> /// </remarks> public virtual IEnumerable <string> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current) { // will not use cache if previewing var route = umbracoContext.ContentCache.GetRouteById(id); if (string.IsNullOrWhiteSpace(route)) { LogHelper.Debug <DefaultUrlProvider>( "Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.", () => id); return(null); } if (route.StartsWith("err/")) { return(null); } var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); // extract domainUri and path // route is /<path> or <domainRootId>/<path> var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); var domainUris = pos == 0 ? null : domainHelper.DomainsForNode(int.Parse(route.Substring(0, pos)), current); // assemble the alternate urls from domainUris (maybe empty) and path return(AssembleUrls(domainUris, path).Select(uri => uri.ToString())); }
/// <summary> /// Looks for wildcard domains in the path and updates <c>Culture</c> accordingly. /// </summary> internal void HandleWildcardDomains() { const string tracePrefix = "HandleWildcardDomains: "; if (!_pcr.HasPublishedContent) { return; } 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(DomainHelper.GetAllDomains(true), nodePath, rootNodeId); if (domain != null) { _pcr.Culture = new CultureInfo(domain.Language.CultureAlias); LogHelper.Debug <PublishedContentRequestEngine>("{0}Got domain on node {1}, set culture to \"{2}\".", () => tracePrefix, () => domain.RootNodeId, () => _pcr.Culture.Name); } else { LogHelper.Debug <PublishedContentRequestEngine>("{0}No match.", () => tracePrefix); } }
/// <summary> /// Gets the nice url of a published content. /// </summary> /// <param name="umbracoContext">The Umbraco context.</param> /// <param name="id">The published content id.</param> /// <param name="current">The current absolute url.</param> /// <param name="mode">The url mode.</param> /// <returns>The url for the published content.</returns> /// <remarks> /// <para>The url is absolute or relative depending on <c>mode</c> and on <c>current</c>.</para> /// <para>If the provider is unable to provide a url, it should return <c>null</c>.</para> /// </remarks> public virtual string GetUrl(UmbracoContext umbracoContext, int id, Uri current, UrlProviderMode mode) { if (!current.IsAbsoluteUri) { throw new ArgumentException("Current url must be absolute.", "current"); } // will not use cache if previewing var route = umbracoContext.ContentCache.GetRouteById(id); if (string.IsNullOrWhiteSpace(route)) { LogHelper.Debug <DefaultUrlProvider>( "Couldn't find any page with nodeId={0}. This is most likely caused by the page not being published.", () => id); return(null); } var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); // extract domainUri and path // route is /<path> or <domainRootId>/<path> var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); var domainUri = pos == 0 ? null : domainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current); // assemble the url from domainUri (maybe null) and path return(AssembleUrl(domainUri, path, current, mode).ToString()); }
/// <summary> /// Looks for wildcard domains in the path and updates <c>Culture</c> accordingly. /// </summary> private void HandleWildcardDomains() { const string tracePrefix = "HandleWildcardDomains: "; if (!_publishedContentRequest.HasNode) { return; } var nodePath = _publishedContentRequest.PublishedContent.Path; LogHelper.Debug <PublishedContentRequest>("{0}Path=\"{1}\"", () => tracePrefix, () => nodePath); var rootNodeId = _publishedContentRequest.HasDomain ? _publishedContentRequest.Domain.RootNodeId : (int?)null; var domain = DomainHelper.LookForWildcardDomain(Domain.GetDomains(), nodePath, rootNodeId); if (domain != null) { _publishedContentRequest.Culture = new CultureInfo(domain.Language.CultureAlias); LogHelper.Debug <PublishedContentRequest>("{0}Got domain on node {1}, set culture to \"{2}\".", () => tracePrefix, () => domain.RootNodeId, () => _publishedContentRequest.Culture.Name); } else { LogHelper.Debug <PublishedContentRequest>("{0}No match.", () => tracePrefix); } }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedRequest</c>. /// </summary> /// <param name="frequest">The <c>PublishedRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> /// <remarks>If successful, also assigns the template.</remarks> public override bool TryFindContent(PublishedRequest frequest) { IPublishedContent node = null; var path = frequest.Uri.GetAbsolutePathDecoded(); if (frequest.HasDomain) { path = DomainHelper.PathRelativeToDomain(frequest.Domain.Uri, path); } // no template if "/" if (path == "/") { Logger.Debug <ContentFinderByUrlAndTemplate>("No template in path '/'"); return(false); } // look for template in last position var pos = path.LastIndexOf('/'); var templateAlias = path.Substring(pos + 1); path = pos == 0 ? "/" : path.Substring(0, pos); var template = _fileService.GetTemplate(templateAlias); if (template == null) { Logger.Debug <ContentFinderByUrlAndTemplate>("Not a valid template: '{TemplateAlias}'", templateAlias); return(false); } Logger.Debug <ContentFinderByUrlAndTemplate>("Valid template: '{TemplateAlias}'", templateAlias); // look for node corresponding to the rest of the route var route = frequest.HasDomain ? (frequest.Domain.ContentId + path) : path; node = FindContent(frequest, route); // also assigns to published request if (node == null) { Logger.Debug <ContentFinderByUrlAndTemplate>("Not a valid route to node: '{Route}'", route); return(false); } // IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings if (!node.IsAllowedTemplate(template.Id)) { Logger.Warn <ContentFinderByUrlAndTemplate>("Alternative template '{TemplateAlias}' is not allowed on node {NodeId}.", template.Alias, node.Id); frequest.PublishedContent = null; // clear return(false); } // got it frequest.TemplateModel = template; return(true); }
Uri DomainUriAtNode(int nodeId, Uri current) { // be safe if (nodeId <= 0) { return(null); } // apply filter on domains defined on that node var domainAndUri = DomainHelper.DomainMatch(Domain.GetDomainsById(nodeId), current, true); return(domainAndUri == null ? null : domainAndUri.Uri); }
/// <summary> /// Initializes a new instance of the <see cref="DomainAndUri"/> class. /// </summary> /// <param name="domain">The original domain.</param> /// <param name="currentUri">The context current Uri.</param> public DomainAndUri(Domain domain, Uri currentUri) : base(domain) { try { Uri = DomainHelper.ParseUriFromDomainName(Name, currentUri); } catch (UriFormatException) { throw new ArgumentException($"Failed to parse invalid domain: node id={domain.ContentId}, hostname=\"{Name.ToCSharpString()}\"." + " Hostname should be a valid uri.", nameof(domain)); } }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="docRequest">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> /// <remarks>If successful, also assigns the template.</remarks> public override bool TryFindContent(PublishedContentRequest docRequest) { const string tracePrefix = "ContentFinderByNiceUrlAndTemplate: "; IPublishedContent node = null; string path = docRequest.Uri.GetAbsolutePathDecoded(); if (docRequest.HasDomain) { path = DomainHelper.PathRelativeToDomain(docRequest.DomainUri, path); } if (path != "/") // no template if "/" { var pos = path.LastIndexOf('/'); var templateAlias = path.Substring(pos + 1); path = pos == 0 ? "/" : path.Substring(0, pos); var template = ApplicationContext.Current.Services.FileService.GetTemplate(templateAlias); if (template != null) { LogHelper.Debug <ContentFinderByNiceUrlAndTemplate>("Valid template: \"{0}\"", () => templateAlias); var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path; node = FindContent(docRequest, route); if (node.IsAllowedTemplate(template.Id)) { docRequest.TemplateModel = template; } else { LogHelper.Warn <ContentFinderByNiceUrlAndTemplate>("Configuration settings prevent template \"{0}\" from showing for node \"{1}\"", () => templateAlias, () => node.Id); docRequest.PublishedContent = null; node = null; } } else { LogHelper.Debug <ContentFinderByNiceUrlAndTemplate>("Not a valid template: \"{0}\"", () => templateAlias); } } else { LogHelper.Debug <ContentFinderByNiceUrlAndTemplate>("No template in path \"/\""); } return(node != null); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="frequest">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> public virtual bool TryFindContent(PublishedRequest frequest) { string route; if (frequest.HasDomain) { route = frequest.Domain.ContentId + DomainHelper.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded()); } else { route = frequest.Uri.GetAbsolutePathDecoded(); } var node = FindContent(frequest, route); return(node != null); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="docRequest">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> public virtual bool TrySetDocument(PublishedContentRequest docRequest) { string route; if (docRequest.HasDomain) { route = docRequest.Domain.RootNodeId.ToString() + DomainHelper.PathRelativeToDomain(docRequest.DomainUri, docRequest.Uri.GetAbsolutePathDecoded()); } else { route = docRequest.Uri.GetAbsolutePathDecoded(); } var node = LookupDocumentNode(docRequest, route); return(node != null); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="contentRequest">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> /// <remarks>Optionally, can also assign the template or anything else on the document request, although that is not required.</remarks> public bool TryFindContent(PublishedContentRequest contentRequest) { var route = contentRequest.HasDomain ? contentRequest.UmbracoDomain.RootContentId + DomainHelper.PathRelativeToDomain(contentRequest.DomainUri, contentRequest.Uri.GetAbsolutePathDecoded()) : contentRequest.Uri.GetAbsolutePathDecoded(); var service = contentRequest.RoutingContext.UmbracoContext.Application.Services.RedirectUrlService; var redirectUrl = service.GetMostRecentRedirectUrl(route); if (redirectUrl == null) { LogHelper.Debug <ContentFinderByRedirectUrl>("No match for route: \"{0}\".", () => route); return(false); } var content = contentRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectUrl.ContentId); var url = content == null ? "#" : content.Url; if (url.StartsWith("#")) { LogHelper.Debug <ContentFinderByRedirectUrl>("Route \"{0}\" matches content {1} which has no url.", () => route, () => redirectUrl.ContentId); return(false); } // Apending any querystring from the incoming request to the redirect url. url = string.IsNullOrEmpty(contentRequest.Uri.Query) ? url : url + contentRequest.Uri.Query; LogHelper.Debug <ContentFinderByRedirectUrl>("Route \"{0}\" matches content {1} with url \"{2}\", redirecting.", () => route, () => content.Id, () => url); // From: http://stackoverflow.com/a/22468386/5018 // See http://issues.umbraco.org/issue/U4-8361#comment=67-30532 // Setting automatic 301 redirects to not be cached because browsers cache these very aggressively which then leads // to problems if you rename a page back to it's original name or create a new page with the original name contentRequest.Cacheability = HttpCacheability.NoCache; contentRequest.CacheExtensions = new List <string> { "no-store, must-revalidate" }; contentRequest.Headers = new Dictionary <string, string> { { "Pragma", "no-cache" }, { "Expires", "0" } }; contentRequest.SetRedirectPermanent(url); return(true); }
/// <summary> /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. /// </summary> /// <returns>A value indicating whether a domain was found.</returns> internal bool FindDomain() { const string tracePrefix = "FindDomain: "; // note - we are not handling schemes nor ports here. LogHelper.Debug <PublishedContentRequestEngine>("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri); // try to find a domain matching the current request var domainAndUri = DomainHelper.DomainForUri(DomainHelper.GetAllDomains(false), _pcr.Uri); // handle domain if (domainAndUri != null) { // matching an existing domain LogHelper.Debug <PublishedContentRequestEngine>("{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"", () => tracePrefix, () => domainAndUri.Domain.Name, () => domainAndUri.Domain.RootNodeId, () => domainAndUri.Domain.Language.CultureAlias); _pcr.Domain = domainAndUri.Domain; _pcr.DomainUri = domainAndUri.Uri; _pcr.Culture = new CultureInfo(domainAndUri.Domain.Language.CultureAlias); // canonical? not implemented at the moment // if (...) // { // _pcr.RedirectUrl = "..."; // return true; // } } else { // not matching any existing domain LogHelper.Debug <PublishedContentRequestEngine>("{0}Matches no domain", () => tracePrefix); var defaultLanguage = Language.GetAllAsList().FirstOrDefault(); _pcr.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.CultureAlias); } LogHelper.Debug <PublishedContentRequestEngine>("{0}Culture=\"{1}\"", () => tracePrefix, () => _pcr.Culture.Name); return(_pcr.Domain != null); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="docRequest">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> /// <remarks>If successful, also assigns the template.</remarks> public override bool TrySetDocument(PublishedContentRequest docRequest) { IPublishedContent node = null; string path = docRequest.Uri.GetAbsolutePathDecoded(); if (docRequest.HasDomain) { path = DomainHelper.PathRelativeToDomain(docRequest.DomainUri, path); } if (path != "/") // no template if "/" { var pos = path.LastIndexOf('/'); var templateAlias = path.Substring(pos + 1); path = pos == 0 ? "/" : path.Substring(0, pos); //TODO: We need to check if the altTemplate is for MVC or not, though I'm not exactly sure how the best // way to do that would be since the template is just an alias and if we are not having a flag on the // doc type for rendering engine and basing it only on template name, then how would we handle this? var template = Template.GetByAlias(templateAlias); if (template != null) { LogHelper.Debug <LookupByNiceUrlAndTemplate>("Valid template: \"{0}\"", () => templateAlias); var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path; node = LookupDocumentNode(docRequest, route); if (node != null) { docRequest.Template = template; } } else { LogHelper.Debug <LookupByNiceUrlAndTemplate>("Not a valid template: \"{0}\"", () => templateAlias); } } else { LogHelper.Debug <LookupByNiceUrlAndTemplate>("No template in path \"/\""); } return(node != null); }
/// <summary> /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. /// </summary> /// <returns>A value indicating whether a domain was found.</returns> internal bool FindDomain() { const string tracePrefix = "FindDomain: "; // note - we are not handling schemes nor ports here. ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}Uri=\"{1}\"", () => tracePrefix, () => _pcr.Uri); // try to find a domain matching the current request var domainAndUri = DomainHelper.DomainForUri(Services.DomainService.GetAll(false), _pcr.Uri); // handle domain if (domainAndUri != null && domainAndUri.UmbracoDomain.LanguageIsoCode.IsNullOrWhiteSpace() == false) { // matching an existing domain ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}Matches domain=\"{1}\", rootId={2}, culture=\"{3}\"", () => tracePrefix, () => domainAndUri.UmbracoDomain.DomainName, () => domainAndUri.UmbracoDomain.RootContentId, () => domainAndUri.UmbracoDomain.LanguageIsoCode); _pcr.UmbracoDomain = domainAndUri.UmbracoDomain; _pcr.DomainUri = domainAndUri.Uri; _pcr.Culture = new CultureInfo(domainAndUri.UmbracoDomain.LanguageIsoCode); // canonical? not implemented at the moment // if (...) // { // _pcr.RedirectUrl = "..."; // return true; // } } else { // not matching any existing domain ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}Matches no domain", () => tracePrefix); var defaultLanguage = Services.LocalizationService.GetAllLanguages().FirstOrDefault(); _pcr.Culture = defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode); } ProfilingLogger.Logger.Debug <PublishedContentRequestEngine>("{0}Culture=\"{1}\"", () => tracePrefix, () => _pcr.Culture.Name); return(_pcr.UmbracoDomain != null); }
/// <summary> /// Gets the other urls of a published content. /// </summary> /// <param name="umbracoContext">The Umbraco context.</param> /// <param name="id">The published content id.</param> /// <param name="current">The current absolute url.</param> /// <returns>The other urls for the published content.</returns> /// <remarks> /// <para>Other urls are those that <c>GetUrl</c> would not return in the current context, but would be valid /// urls for the node in other contexts (different domain for current request, umbracoUrlAlias...).</para> /// </remarks> public IEnumerable <string> GetOtherUrls(UmbracoContext umbracoContext, int id, Uri current) { if (!FindByUrlAliasEnabled) { return(Enumerable.Empty <string>()); // we have nothing to say } var node = umbracoContext.ContentCache.GetById(id); string umbracoUrlName = null; if (node.HasProperty(Constants.Conventions.Content.UrlAlias)) { umbracoUrlName = node.GetPropertyValue <string>(Constants.Conventions.Content.UrlAlias); } if (string.IsNullOrWhiteSpace(umbracoUrlName)) { return(Enumerable.Empty <string>()); } var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); var n = node; 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, false); } var path = "/" + umbracoUrlName; if (domainUris == null) { var uri = new Uri(path, UriKind.Relative); return(new[] { UriUtility.UriFromUmbraco(uri).ToString() }); } return(domainUris .Select(domainUri => new Uri(CombinePaths(domainUri.Uri.GetLeftPart(UriPartial.Path), path))) .Select(uri => UriUtility.UriFromUmbraco(uri).ToString())); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="docRequest">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> /// <remarks>If successful, also assigns the template.</remarks> public override bool TryFindContent(PublishedContentRequest docRequest) { IPublishedContent node = null; string path = docRequest.Uri.GetAbsolutePathDecoded(); if (docRequest.HasDomain) { path = DomainHelper.PathRelativeToDomain(docRequest.DomainUri, path); } if (path != "/") // no template if "/" { var pos = path.LastIndexOf('/'); var templateAlias = path.Substring(pos + 1); path = pos == 0 ? "/" : path.Substring(0, pos); var template = ApplicationContext.Current.Services.FileService.GetTemplate(templateAlias); if (template != null) { LogHelper.Debug <ContentFinderByNiceUrlAndTemplate>("Valid template: \"{0}\"", () => templateAlias); var route = docRequest.HasDomain ? (docRequest.Domain.RootNodeId.ToString() + path) : path; node = FindContent(docRequest, route); if (UmbracoConfig.For.UmbracoSettings().WebRouting.DisableAlternativeTemplates == false && node != null) { docRequest.TemplateModel = template; } } else { LogHelper.Debug <ContentFinderByNiceUrlAndTemplate>("Not a valid template: \"{0}\"", () => templateAlias); } } else { LogHelper.Debug <ContentFinderByNiceUrlAndTemplate>("No template in path \"/\""); } return(node != null); }
IEnumerable <Uri> DomainUrisAtNode(int nodeId, Uri current) { // be safe if (nodeId <= 0) { return new Uri[] { } } ; var domainAndUris = DomainHelper.DomainMatches(Domain.GetDomainsById(nodeId), current); return(domainAndUris.Select(d => d.Uri)); } void ApplyHideTopLevelNodeFromPath(Core.Models.IPublishedContent node, List <string> pathParts) { // in theory if hideTopLevelNodeFromPath is true, then there should be only once // top-level node, or else domains should be assigned. but for backward compatibility // we add this check - we look for the document matching "/" and if it's not us, then // we do not hide the top level path // it has to be taken care of in IPublishedContentStore.GetDocumentByRoute too so if // "/foo" fails (looking for "/*/foo") we try also "/foo". // this does not make much sense anyway esp. if both "/foo/" and "/bar/foo" exist, but // that's the way it works pre-4.10 and we try to be backward compat for the time being if (node.Parent == null) { var rootNode = _publishedContentStore.GetDocumentByRoute(_umbracoContext, "/", true); if (rootNode.Id == node.Id) // remove only if we're the default node { pathParts.RemoveAt(pathParts.Count - 1); } } else { pathParts.RemoveAt(pathParts.Count - 1); } } #endregion }
/// <summary> /// Tries to find an Umbraco document for a <c>PublishedContentRequest</c> and a route. /// </summary> /// <param name="docreq">The document request.</param> /// <param name="route">The route.</param> /// <returns>The document node, or null.</returns> protected IPublishedContent LookupDocumentNode(PublishedContentRequest docreq, string route) { LogHelper.Debug <LookupByNiceUrl>("Test route \"{0}\"", () => route); // first ask the cache for a node // return '0' if in preview mode var nodeId = !docreq.RoutingContext.UmbracoContext.InPreviewMode ? docreq.RoutingContext.UmbracoContext.RoutesCache.GetNodeId(route) : 0; // if a node was found, get it by id and ensure it exists // else clear the cache IPublishedContent node = null; if (nodeId > 0) { node = docreq.RoutingContext.PublishedContentStore.GetDocumentById( docreq.RoutingContext.UmbracoContext, nodeId); if (node != null) { docreq.PublishedContent = node; LogHelper.Debug <LookupByNiceUrl>("Cache hit, id={0}", () => nodeId); } else { docreq.RoutingContext.UmbracoContext.RoutesCache.ClearNode(nodeId); } } // if we still have no node, get it by route if (node == null) { LogHelper.Debug <LookupByNiceUrl>("Cache miss, query"); node = docreq.RoutingContext.PublishedContentStore.GetDocumentByRoute( docreq.RoutingContext.UmbracoContext, route); if (node != null) { docreq.PublishedContent = node; LogHelper.Debug <LookupByNiceUrl>("Query matches, id={0}", () => docreq.DocumentId); var iscanon = true; if (docreq.HasDomain) { iscanon = !DomainHelper.ExistsDomainInPath(docreq.Domain, node.Path); if (!iscanon) { LogHelper.Debug <LookupByNiceUrl>("Non canonical url"); } } // do not store if previewing or if non-canonical if (!docreq.RoutingContext.UmbracoContext.InPreviewMode && iscanon) { docreq.RoutingContext.UmbracoContext.RoutesCache.Store(docreq.DocumentId, route); } } else { LogHelper.Debug <LookupByNiceUrl>("Query does not match"); } } return(node); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedRequest</c>. /// </summary> /// <param name="frequest">The <c>PublishedRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> public bool TryFindContent(PublishedRequest frequest) { _logger.Debug <ContentFinderByConfigured404>("Looking for a page to handle 404."); // try to find a culture as best as we can var errorCulture = CultureInfo.CurrentUICulture; if (frequest.HasDomain) { errorCulture = frequest.Domain.Culture; } else { var route = frequest.Uri.GetAbsolutePathDecoded(); var pos = route.LastIndexOf('/'); IPublishedContent node = null; while (pos > 1) { route = route.Substring(0, pos); node = frequest.UmbracoContext.ContentCache.GetByRoute(route, culture: frequest?.Culture?.Name); if (node != null) { break; } pos = route.LastIndexOf('/'); } if (node != null) { var d = DomainHelper.FindWildcardDomainInPath(frequest.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), node.Path, null); if (d != null) { errorCulture = d.Culture; } } } var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId( _contentConfigSection.Error404Collection.ToArray(), _entityService, new PublishedContentQuery(frequest.UmbracoContext.PublishedSnapshot, frequest.UmbracoContext.VariationContextAccessor), errorCulture); IPublishedContent content = null; if (error404.HasValue) { _logger.Debug <ContentFinderByConfigured404>("Got id={ErrorNodeId}.", error404.Value); content = frequest.UmbracoContext.ContentCache.GetById(error404.Value); _logger.Debug <ContentFinderByConfigured404>(content == null ? "Could not find content with that id." : "Found corresponding content."); } else { _logger.Debug <ContentFinderByConfigured404>("Got nothing."); } frequest.PublishedContent = content; frequest.Is404 = true; return(content != null); }
/// <summary> /// Finds the site root (if any) matching the http request, and updates the PublishedContentRequest accordingly. /// </summary> /// <returns>A value indicating whether a domain was found.</returns> internal bool FindDomain(PublishedRequest request) { const string tracePrefix = "FindDomain: "; // note - we are not handling schemes nor ports here. _logger.Debug <PublishedRouter>("{TracePrefix}Uri={RequestUri}", tracePrefix, request.Uri); var domainsCache = request.UmbracoContext.PublishedSnapshot.Domains; var domains = domainsCache.GetAll(includeWildcards: false).ToList(); // determines whether a domain corresponds to a published document, since some // domains may exist but on a document that has been unpublished - as a whole - or // that is not published for the domain's culture - in which case the domain does // not apply bool IsPublishedContentDomain(Domain domain) { // just get it from content cache - optimize there, not here var domainDocument = request.UmbracoContext.PublishedSnapshot.Content.GetById(domain.ContentId); // not published - at all if (domainDocument == null) { return(false); } // invariant - always published if (!domainDocument.ContentType.VariesByCulture()) { return(true); } // variant, ensure that the culture corresponding to the domain's language is published return(domainDocument.Cultures.ContainsKey(domain.Culture.Name)); } domains = domains.Where(IsPublishedContentDomain).ToList(); var defaultCulture = domainsCache.DefaultCulture; // try to find a domain matching the current request var domainAndUri = DomainHelper.SelectDomain(domains, request.Uri, defaultCulture: defaultCulture); // handle domain - always has a contentId and a culture if (domainAndUri != null) { // matching an existing domain _logger.Debug <PublishedRouter>("{TracePrefix}Matches domain={Domain}, rootId={RootContentId}, culture={Culture}", tracePrefix, domainAndUri.Name, domainAndUri.ContentId, domainAndUri.Culture); request.Domain = domainAndUri; request.Culture = domainAndUri.Culture; // canonical? not implemented at the moment // if (...) // { // _pcr.RedirectUrl = "..."; // return true; // } } else { // not matching any existing domain _logger.Debug <PublishedRouter>("{TracePrefix}Matches no domain", tracePrefix); request.Culture = defaultCulture == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultCulture); } _logger.Debug <PublishedRouter>("{TracePrefix}Culture={CultureName}", tracePrefix, request.Culture.Name); return(request.Domain != null); }
/// <summary> /// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>. /// </summary> /// <param name="pcr">The <c>PublishedContentRequest</c>.</param> /// <returns>A value indicating whether an Umbraco document was found and assigned.</returns> public bool TryFindContent(PublishedContentRequest pcr) { LogHelper.Debug <ContentFinderByLegacy404>("Looking for a page to handle 404."); // try to find a culture as best as we can var errorCulture = CultureInfo.CurrentUICulture; if (pcr.HasDomain) { errorCulture = CultureInfo.GetCultureInfo(pcr.UmbracoDomain.LanguageIsoCode); } else { var route = pcr.Uri.GetAbsolutePathDecoded(); var pos = route.LastIndexOf('/'); IPublishedContent node = null; while (pos > 1) { route = route.Substring(0, pos); node = pcr.RoutingContext.UmbracoContext.ContentCache.GetByRoute(route); if (node != null) { break; } pos = route.LastIndexOf('/'); } if (node != null) { var d = DomainHelper.FindWildcardDomainInPath(pcr.RoutingContext.UmbracoContext.Application.Services.DomainService.GetAll(true), node.Path, null); if (d != null && string.IsNullOrWhiteSpace(d.LanguageIsoCode) == false) { errorCulture = CultureInfo.GetCultureInfo(d.LanguageIsoCode); } } } // TODO - replace the whole logic var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId( //TODO: The IContentSection should be ctor injected into this class in v8! UmbracoConfig.For.UmbracoSettings().Content.Error404Collection.ToArray(), pcr.RoutingContext.UmbracoContext.Application.Services.EntityService, new PublishedContentQuery(pcr.RoutingContext.UmbracoContext.ContentCache, pcr.RoutingContext.UmbracoContext.MediaCache), errorCulture); IPublishedContent content = null; if (error404.HasValue) { LogHelper.Debug <ContentFinderByLegacy404>("Got id={0}.", () => error404.Value); content = pcr.RoutingContext.UmbracoContext.ContentCache.GetById(error404.Value); LogHelper.Debug <ContentFinderByLegacy404>(content == null ? "Could not find content with that id." : "Found corresponding content."); } else { LogHelper.Debug <ContentFinderByLegacy404>("Got nothing."); } pcr.PublishedContent = content; pcr.SetIs404(); return(content != null); }