コード例 #1
0
        /// <summary>
        /// Tries to find the document matching the request, by running the IPublishedContentFinder instances.
        /// </summary>
        /// <exception cref="InvalidOperationException">There is no finder collection.</exception>
        internal void FindPublishedContent(PublishedRequest request)
        {
            const string tracePrefix = "FindPublishedContent: ";

            // look for the document
            // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template
            // some finders may implement caching

            using (_profilingLogger.DebugDuration <PublishedRouter>(
                       $"{tracePrefix}Executing finders...",
                       $"{tracePrefix}Completed executing finders"))
            {
                //iterate but return on first one that finds it
                var found = _contentFinders.Any(finder =>
                {
                    _logger.Debug <PublishedRouter>("Finder {ContentFinderType}", finder.GetType().FullName);
                    return(finder.TryFindContent(request));
                });

                _profilingLogger.Debug <PublishedRouter>(
                    "Found? {Found} Content: {PublishedContentId}, Template: {TemplateAlias}, Domain: {Domain}, Culture: {Culture}, Is404: {Is404}, StatusCode: {StatusCode}",
                    found,
                    request.HasPublishedContent ? request.PublishedContent.Id : "NULL",
                    request.HasTemplate ? request.TemplateAlias : "NULL",
                    request.HasDomain ? request.Domain.ToString() : "NULL",
                    request.Culture?.Name ?? "NULL",
                    request.Is404,
                    request.ResponseStatusCode);
            }

            // indicate that the published content (if any) we have at the moment is the
            // one that was found by the standard finders before anything else took place.
            request.SetIsInitialPublishedContent();
        }
コード例 #2
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Follows external redirection through <c>umbracoRedirect</c> document property.
        /// </summary>
        /// <remarks>As per legacy, if the redirect does not work, we just ignore it.</remarks>
        private void FollowExternalRedirect(PublishedRequest request)
        {
            if (request.HasPublishedContent == false)
            {
                return;
            }

            // don't try to find a redirect if the property doesn't exist
            if (request.PublishedContent.HasProperty(Constants.Conventions.Content.Redirect) == false)
            {
                return;
            }

            var redirectId  = request.PublishedContent.Value(Constants.Conventions.Content.Redirect, defaultValue: -1);
            var redirectUrl = "#";

            if (redirectId > 0)
            {
                redirectUrl = request.UmbracoContext.UrlProvider.GetUrl(redirectId);
            }
            else
            {
                // might be a UDI instead of an int Id
                var redirectUdi = request.PublishedContent.Value <GuidUdi>(Constants.Conventions.Content.Redirect);
                if (redirectUdi != null)
                {
                    redirectUrl = request.UmbracoContext.UrlProvider.GetUrl(redirectUdi.Guid);
                }
            }
            if (redirectUrl != "#")
            {
                request.SetRedirect(redirectUrl);
            }
        }
コード例 #3
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <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     = DomainUtilities.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);
            }
        }
コード例 #4
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <inheritdoc />
        public bool TryRouteRequest(PublishedRequest request)
        {
            // disabled - is it going to change the routing?
            //_pcr.OnPreparing();

            FindDomain(request);
            if (request.IsRedirect)
            {
                return(false);
            }
            if (request.HasPublishedContent)
            {
                return(true);
            }
            FindPublishedContent(request);
            if (request.IsRedirect)
            {
                return(false);
            }

            // don't handle anything - we just want to ensure that we find the content
            //HandlePublishedContent();
            //FindTemplate();
            //FollowExternalRedirect();
            //HandleWildcardDomains();

            // disabled - we just want to ensure that we find the content
            //_pcr.OnPrepared();

            return(request.HasPublishedContent);
        }
コード例 #5
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Finds the Umbraco document (if any) matching the request, and updates the PublishedRequest accordingly.
        /// </summary>
        /// <returns>A value indicating whether a document and template were found.</returns>
        private void FindPublishedContentAndTemplate(PublishedRequest request)
        {
            _logger.Debug <PublishedRouter>("FindPublishedContentAndTemplate: Path={UriAbsolutePath}", request.Uri.AbsolutePath);

            // run the document finders
            FindPublishedContent(request);

            // if request has been flagged to redirect then return
            // whoever called us is in charge of actually redirecting
            // -- do not process anything any further --
            if (request.IsRedirect)
            {
                return;
            }

            // not handling umbracoRedirect here but after LookupDocument2
            // so internal redirect, 404, etc has precedence over redirect

            // handle not-found, redirects, access...
            HandlePublishedContent(request);

            // find a template
            FindTemplate(request);

            // handle umbracoRedirect
            FollowExternalRedirect(request);
        }
コード例 #6
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <inheritdoc />
        public bool PrepareRequest(PublishedRequest request)
        {
            // note - at that point the original legacy module did something do handle IIS custom 404 errors
            //   ie pages looking like /anything.aspx?404;/path/to/document - I guess the reason was to support
            //   "directory urls" without having to do wildcard mapping to ASP.NET on old IIS. This is a pain
            //   to maintain and probably not used anymore - removed as of 06/2012. @zpqrtbnk.
            //
            //   to trigger Umbraco's not-found, one should configure IIS and/or ASP.NET custom 404 errors
            //   so that they point to a non-existing page eg /redirect-404.aspx
            //   TODO: SD: We need more information on this for when we release 4.10.0 as I'm not sure what this means.

            // trigger the Preparing event - at that point anything can still be changed
            // the idea is that it is possible to change the uri
            //
            request.OnPreparing();

            //find domain
            FindDomain(request);

            // if request has been flagged to redirect then return
            // whoever called us is in charge of actually redirecting
            if (request.IsRedirect)
            {
                return(false);
            }

            // set the culture on the thread - once, so it's set when running document lookups
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = request.Culture;
            SetVariationContext(request.Culture.Name);

            //find the published content if it's not assigned. This could be manually assigned with a custom route handler, or
            // with something like EnsurePublishedContentRequestAttribute or UmbracoVirtualNodeRouteHandler. Those in turn call this method
            // to setup the rest of the pipeline but we don't want to run the finders since there's one assigned.
            if (request.PublishedContent == null)
            {
                // find the document & template
                FindPublishedContentAndTemplate(request);
            }

            // handle wildcard domains
            HandleWildcardDomains(request);

            // set the culture on the thread -- again, 'cos it might have changed due to a finder or wildcard domain
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = request.Culture;
            SetVariationContext(request.Culture.Name);

            // trigger the Prepared event - at that point it is still possible to change about anything
            // even though the request might be flagged for redirection - we'll redirect _after_ the event
            //
            // also, OnPrepared() will make the PublishedRequest readonly, so nothing can change
            //
            request.OnPrepared();

            // we don't take care of anything so if the content has changed, it's up to the user
            // to find out the appropriate template

            //complete the PCR and assign the remaining values
            return(ConfigureRequest(request));
        }
コード例 #7
0
        /// <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 = DomainUtilities.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, string>("Not a valid template: '{TemplateAlias}'", templateAlias);
                return(false);
            }

            Logger.Debug <ContentFinderByUrlAndTemplate, string>("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, string>("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, string, int>("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);
        }
コード例 #8
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Handles the published content (if any).
        /// </summary>
        /// <remarks>
        /// Handles "not found", internal redirects, access validation...
        /// things that must be handled in one place because they can create loops
        /// </remarks>
        private void HandlePublishedContent(PublishedRequest request)
        {
            // because these might loop, we have to have some sort of infinite loop detection
            int       i = 0, j = 0;
            const int maxLoop = 8;

            do
            {
                _logger.Debug <PublishedRouter>("HandlePublishedContent: Loop {LoopCounter}", i);

                // handle not found
                if (request.HasPublishedContent == false)
                {
                    request.Is404 = true;
                    _logger.Debug <PublishedRouter>("HandlePublishedContent: No document, try last chance lookup");

                    // if it fails then give up, there isn't much more that we can do
                    if (_contentLastChanceFinder.TryFindContent(request) == false)
                    {
                        _logger.Debug <PublishedRouter>("HandlePublishedContent: Failed to find a document, give up");
                        break;
                    }

                    _logger.Debug <PublishedRouter>("HandlePublishedContent: Found a document");
                }

                // follow internal redirects as long as it's not running out of control ie infinite loop of some sort
                j = 0;
                while (FollowInternalRedirects(request) && j++ < maxLoop)
                {
                }
                if (j == maxLoop) // we're running out of control
                {
                    break;
                }

                // ensure access
                if (request.HasPublishedContent)
                {
                    EnsurePublishedContentAccess(request);
                }

                // loop while we don't have page, ie the redirect or access
                // got us to nowhere and now we need to run the notFoundLookup again
                // as long as it's not running out of control ie infinite loop of some sort
            } while (request.HasPublishedContent == false && i++ < maxLoop);

            if (i == maxLoop || j == maxLoop)
            {
                _logger.Debug <PublishedRouter>("HandlePublishedContent: Looks like we are running into an infinite loop, abort");
                request.PublishedContent = null;
            }

            _logger.Debug <PublishedRouter>("HandlePublishedContent: End");
        }
コード例 #9
0
        /// <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)
        {
            if (frequest.UmbracoContext != null && frequest.UmbracoContext.InPreviewMode == false &&
                _webRoutingSection.DisableFindContentByIdPath)
            {
                return(false);
            }

            IPublishedContent node = null;
            var path = frequest.Uri.GetAbsolutePathDecoded();

            var nodeId = -1;

            if (path != "/") // no id if "/"
            {
                var noSlashPath = path.Substring(1);

                if (int.TryParse(noSlashPath, out nodeId) == false)
                {
                    nodeId = -1;
                }

                if (nodeId > 0)
                {
                    _logger.Debug <ContentFinderByIdPath>("Id={NodeId}", nodeId);
                    node = frequest.UmbracoContext.Content.GetById(nodeId);

                    if (node != null)
                    {
                        //if we have a node, check if we have a culture in the query string
                        if (frequest.UmbracoContext.HttpContext.Request.QueryString.ContainsKey("culture"))
                        {
                            //we're assuming it will match a culture, if an invalid one is passed in, an exception will throw (there is no TryGetCultureInfo method), i think this is ok though
                            frequest.Culture = CultureInfo.GetCultureInfo(frequest.UmbracoContext.HttpContext.Request.QueryString["culture"]);
                        }

                        frequest.PublishedContent = node;
                        _logger.Debug <ContentFinderByIdPath>("Found node with id={PublishedContentId}", frequest.PublishedContent.Id);
                    }
                    else
                    {
                        nodeId = -1; // trigger message below
                    }
                }
            }

            if (nodeId == -1)
            {
                _logger.Debug <ContentFinderByIdPath>("Not a node id");
            }

            return(node != null);
        }
コード例 #10
0
        /// <summary>
        /// Follows internal redirections through the <c>umbracoInternalRedirectId</c> document property.
        /// </summary>
        /// <returns>A value indicating whether redirection took place and led to a new published document.</returns>
        /// <remarks>
        /// <para>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</para>
        /// <para>As per legacy, if the redirect does not work, we just ignore it.</para>
        /// </remarks>
        private bool FollowInternalRedirects(PublishedRequest request)
        {
            if (request.PublishedContent == null)
            {
                throw new InvalidOperationException("There is no PublishedContent.");
            }

            // don't try to find a redirect if the property doesn't exist
            if (request.PublishedContent.HasProperty(Constants.Conventions.Content.InternalRedirectId) == false)
            {
                return(false);
            }

            var internalRedirectId = request.PublishedContent.Value(Constants.Conventions.Content.InternalRedirectId)?.ToString();

            if (internalRedirectId == null)
            {
                // no value stored, just return, no need to log
                return(false);
            }

            if (int.TryParse(internalRedirectId, out var internalRedirectIdAsInt) && internalRedirectIdAsInt == request.PublishedContent.Id)
            {
                // redirect to self
                _logger.Debug <PublishedRouter>("FollowInternalRedirects: Redirecting to self, ignore");
                return(false);
            }

            IPublishedContent internalRedirectNode = null;

            if (internalRedirectIdAsInt > 0)
            {
                // try and get the redirect node from a legacy integer ID
                internalRedirectNode = request.UmbracoContext.Content.GetById(internalRedirectIdAsInt);
            }
            else if (GuidUdi.TryParse(internalRedirectId, out var internalRedirectIdAsUdi))
            {
                // try and get the redirect node from a UDI Guid
                internalRedirectNode = request.UmbracoContext.Content.GetById(internalRedirectIdAsUdi.Guid);
            }

            if (internalRedirectNode == null)
            {
                _logger.Debug <PublishedRouter, object>("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: no such published document.",
                                                        request.PublishedContent.GetProperty(Constants.Conventions.Content.InternalRedirectId).GetSourceValue());
                return(false);
            }

            request.SetInternalRedirectPublishedContent(internalRedirectNode); // don't use .PublishedContent here
            _logger.Debug <PublishedRouter, int>("FollowInternalRedirects: Redirecting to id={InternalRedirectId}", internalRedirectIdAsInt);
            return(true);
        }
コード例 #11
0
        /// <summary>
        /// Ensures that access to current node is permitted.
        /// </summary>
        /// <remarks>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</remarks>
        private void EnsurePublishedContentAccess(PublishedRequest request)
        {
            if (request.PublishedContent == null)
            {
                throw new InvalidOperationException("There is no PublishedContent.");
            }

            var path = request.PublishedContent.Path;

            var publicAccessAttempt = _services.PublicAccessService.IsProtected(path);

            if (publicAccessAttempt)
            {
                _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Page is protected, check for access");

                var membershipHelper = Current.Factory.GetInstance <MembershipHelper>();

                if (membershipHelper.IsLoggedIn() == false)
                {
                    _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Not logged in, redirect to login page");

                    var loginPageId = publicAccessAttempt.Result.LoginNodeId;

                    if (loginPageId != request.PublishedContent.Id)
                    {
                        request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(loginPageId);
                    }
                }
                else if (_services.PublicAccessService.HasAccess(request.PublishedContent.Id, _services.ContentService, membershipHelper.CurrentUserName, GetRolesForLogin(membershipHelper.CurrentUserName)) == false)
                {
                    _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Current member has not access, redirect to error page");
                    var errorPageId = publicAccessAttempt.Result.NoAccessNodeId;
                    if (errorPageId != request.PublishedContent.Id)
                    {
                        request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
                    }
                }
                else
                {
                    _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Current member has access");
                }
            }
            else
            {
                _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Page is not protected");
            }
        }
コード例 #12
0
        /// <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>Optionally, can also assign the template or anything else on the document request, although that is not required.</remarks>
        public bool TryFindContent(PublishedRequest frequest)
        {
            var route = frequest.HasDomain
                ? frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded())
                : frequest.Uri.GetAbsolutePathDecoded();



            var redirectUrl = _redirectUrlService.GetMostRecentRedirectUrl(route, frequest.Culture.Name);

            if (redirectUrl == null)
            {
                _logger.Debug <ContentFinderByRedirectUrl, string>("No match for route: {Route}", route);
                return(false);
            }

            var content = frequest.UmbracoContext.Content.GetById(redirectUrl.ContentId);
            var url     = content == null ? "#" : content.Url(redirectUrl.Culture);

            if (url.StartsWith("#"))
            {
                _logger.Debug <ContentFinderByRedirectUrl, string, int>("Route {Route} matches content {ContentId} which has no URL.", route, redirectUrl.ContentId);
                return(false);
            }

            // Appending any querystring from the incoming request to the redirect URL
            url = string.IsNullOrEmpty(frequest.Uri.Query) ? url : url + frequest.Uri.Query;

            _logger.Debug <ContentFinderByRedirectUrl, string, int, string>("Route {Route} matches content {ContentId} with url '{Url}', redirecting.", route, content.Id, url);
            frequest.SetRedirectPermanent(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
            frequest.Cacheability    = HttpCacheability.NoCache;
            frequest.CacheExtensions = new List <string> {
                "no-store, must-revalidate"
            };
            frequest.Headers = new Dictionary <string, string> {
                { "Pragma", "no-cache" }, { "Expires", "0" }
            };

            return(true);
        }
コード例 #13
0
        /// <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);
        }
コード例 #14
0
        /// <summary>
        /// Updates the request when there is no template to render the content.
        /// </summary>
        /// <remarks>This is called from Mvc when there's a document to render but no template.</remarks>
        public void UpdateRequestOnMissingTemplate(PublishedRequest request)
        {
            // clear content
            var content = request.PublishedContent;

            request.PublishedContent = null;

            HandlePublishedContent(request); // will go 404
            FindTemplate(request);

            // if request has been flagged to redirect then return
            // whoever called us is in charge of redirecting
            if (request.IsRedirect)
            {
                return;
            }

            if (request.HasPublishedContent == false)
            {
                // means the engine could not find a proper document to handle 404
                // restore the saved content so we know it exists
                request.PublishedContent = content;
                return;
            }

            if (request.HasTemplate == false)
            {
                // means we may have a document, but we have no template
                // at that point there isn't much we can do and there is no point returning
                // to Mvc since Mvc can't do much either
                return;
            }

            // see note in PrepareRequest()

            // assign the legacy page back to the docrequest
            // handlers like default.aspx will want it and most macros currently need it
            request.UmbracoPage = new page(request);

            // this is used by many legacy objects
            request.UmbracoContext.HttpContext.Items["pageElements"] = request.UmbracoPage.Elements;
        }
コード例 #15
0
        /// <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 bool TryFindContent(PublishedRequest frequest)
        {
            IPublishedContent node = null;

            if (frequest.Uri.AbsolutePath != "/") // no alias if "/"
            {
                node = FindContentByAlias(frequest.UmbracoContext.ContentCache,
                                          frequest.HasDomain ? frequest.Domain.ContentId : 0,
                                          frequest.Culture.Name,
                                          frequest.Uri.GetAbsolutePathDecoded());

                if (node != null)
                {
                    frequest.PublishedContent = node;
                    Logger.Debug <ContentFinderByUrlAlias>("Path '{UriAbsolutePath}' is an alias for id={PublishedContentId}", frequest.Uri.AbsolutePath, frequest.PublishedContent.Id);
                }
            }

            return(node != null);
        }
コード例 #16
0
        /// <summary>
        /// Called by PrepareRequest once everything has been discovered, resolved and assigned to the PCR. This method
        /// finalizes the PCR with the values assigned.
        /// </summary>
        /// <returns>
        /// Returns false if the request was not successfully configured
        /// </returns>
        /// <remarks>
        /// This method logic has been put into it's own method in case developers have created a custom PCR or are assigning their own values
        /// but need to finalize it themselves.
        /// </remarks>
        public bool ConfigureRequest(PublishedRequest frequest)
        {
            if (frequest.HasPublishedContent == false)
            {
                return(false);
            }

            // set the culture on the thread -- again, 'cos it might have changed in the event handler
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture = frequest.Culture;
            SetVariationContext(frequest.Culture.Name);

            // if request has been flagged to redirect, or has no content to display,
            // then return - whoever called us is in charge of actually redirecting
            if (frequest.IsRedirect || frequest.HasPublishedContent == false)
            {
                return(false);
            }

            // we may be 404 _and_ have a content

            // can't go beyond that point without a PublishedContent to render
            // it's ok not to have a template, in order to give MVC a chance to hijack routes

            // note - the page() ctor below will cause the "page" to get the value of all its
            // "elements" ie of all the IPublishedContent property. If we use the object value,
            // that will trigger macro execution - which can't happen because macro execution
            // requires that _pcr.UmbracoPage is already initialized = catch-22. The "legacy"
            // pipeline did _not_ evaluate the macros, ie it is using the data value, and we
            // have to keep doing it because of that catch-22.

            // assign the legacy page back to the request
            // handlers like default.aspx will want it and most macros currently need it
            frequest.UmbracoPage = new page(frequest);

            // used by many legacy objects
            frequest.UmbracoContext.HttpContext.Items["pageElements"] = frequest.UmbracoPage.Elements;

            return(true);
        }
コード例 #17
0
        /// <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 FindContent(PublishedRequest docreq, string route)
        {
            if (docreq == null)
            {
                throw new System.ArgumentNullException(nameof(docreq));
            }

            Logger.Debug <ContentFinderByUrl>("Test route {Route}", route);

            var node = docreq.UmbracoContext.ContentCache.GetByRoute(docreq.UmbracoContext.InPreviewMode, route, culture: docreq.Culture?.Name);

            if (node != null)
            {
                docreq.PublishedContent = node;
                Logger.Debug <ContentFinderByUrl>("Got content, id={NodeId}", node.Id);
            }
            else
            {
                Logger.Debug <ContentFinderByUrl>("No match.");
            }

            return(node);
        }
コード例 #18
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Tries to find the document matching the request, by running the IPublishedContentFinder instances.
        /// </summary>
        /// <exception cref="InvalidOperationException">There is no finder collection.</exception>
        internal void FindPublishedContent(PublishedRequest request)
        {
            const string tracePrefix = "FindPublishedContent: ";

            // look for the document
            // the first successful finder, if any, will set this.PublishedContent, and may also set this.Template
            // some finders may implement caching

            using (_profilingLogger.DebugDuration <PublishedRouter>(
                       $"{tracePrefix}Begin finders",
                       $"{tracePrefix}End finders, {(request.HasPublishedContent ? "a document was found" : "no document was found")}"))
            {
                //iterate but return on first one that finds it
                var found = _contentFinders.Any(finder =>
                {
                    _logger.Debug <PublishedRouter>("Finder {ContentFinderType}", finder.GetType().FullName);
                    return(finder.TryFindContent(request));
                });
            }

            // indicate that the published content (if any) we have at the moment is the
            // one that was found by the standard finders before anything else took place.
            request.SetIsInitialPublishedContent();
        }
コード例 #19
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Finds a template for the current node, if any.
        /// </summary>
        private void FindTemplate(PublishedRequest request)
        {
            // NOTE: at the moment there is only 1 way to find a template, and then ppl must
            // use the Prepared event to change the template if they wish. Should we also
            // implement an ITemplateFinder logic?

            if (request.PublishedContent == null)
            {
                request.TemplateModel = null;
                return;
            }

            // read the alternate template alias, from querystring, form, cookie or server vars,
            // only if the published content is the initial once, else the alternate template
            // does not apply
            // + optionally, apply the alternate template on internal redirects
            var useAltTemplate = request.IsInitialPublishedContent ||
                                 (_webRoutingSection.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent);
            var altTemplate = useAltTemplate
                ? request.UmbracoContext.HttpContext.Request[Constants.Conventions.Url.AltTemplate]
                : null;

            if (string.IsNullOrWhiteSpace(altTemplate))
            {
                // we don't have an alternate template specified. use the current one if there's one already,
                // which can happen if a content lookup also set the template (LookupByNiceUrlAndTemplate...),
                // else lookup the template id on the document then lookup the template with that id.

                if (request.HasTemplate)
                {
                    _logger.Debug <PublishedRequest>("FindTemplate: Has a template already, and no alternate template.");
                    return;
                }

                // TODO: When we remove the need for a database for templates, then this id should be irrelevant,
                // not sure how were going to do this nicely.

                // TODO: We need to limit altTemplate to only allow templates that are assigned to the current document type!
                // if the template isn't assigned to the document type we should log a warning and return 404

                var templateId = request.PublishedContent.TemplateId;
                request.TemplateModel = GetTemplateModel(templateId);
            }
            else
            {
                // we have an alternate template specified. lookup the template with that alias
                // this means the we override any template that a content lookup might have set
                // so /path/to/page/template1?altTemplate=template2 will use template2

                // ignore if the alias does not match - just trace

                if (request.HasTemplate)
                {
                    _logger.Debug <PublishedRouter>("FindTemplate: Has a template already, but also an alternative template.");
                }
                _logger.Debug <PublishedRouter>("FindTemplate: Look for alternative template alias={AltTemplate}", altTemplate);

                // IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings
                if (request.PublishedContent.IsAllowedTemplate(altTemplate))
                {
                    // allowed, use
                    var template = _services.FileService.GetTemplate(altTemplate);

                    if (template != null)
                    {
                        request.TemplateModel = template;
                        _logger.Debug <PublishedRouter>("FindTemplate: Got alternative template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias);
                    }
                    else
                    {
                        _logger.Debug <PublishedRouter>("FindTemplate: The alternative template with alias={AltTemplate} does not exist, ignoring.", altTemplate);
                    }
                }
                else
                {
                    _logger.Warn <PublishedRouter>("FindTemplate: Alternative template {TemplateAlias} is not allowed on node {NodeId}, ignoring.", altTemplate, request.PublishedContent.Id);

                    // no allowed, back to default
                    var templateId = request.PublishedContent.TemplateId;
                    request.TemplateModel = GetTemplateModel(templateId);
                }
            }

            if (request.HasTemplate == false)
            {
                _logger.Debug <PublishedRouter>("FindTemplate: No template was found.");

                // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true
                // then reset _pcr.Document to null to force a 404.
                //
                // but: because we want to let MVC hijack routes even though no template is defined, we decide that
                // a missing template is OK but the request will then be forwarded to MVC, which will need to take
                // care of everything.
                //
                // so, don't set _pcr.Document to null here
            }
            else
            {
                _logger.Debug <PublishedRouter>("FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}", request.TemplateModel.Id, request.TemplateModel.Alias);
            }
        }
コード例 #20
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Ensures that access to current node is permitted.
        /// </summary>
        /// <remarks>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</remarks>
        private void EnsurePublishedContentAccess(PublishedRequest request)
        {
            if (request.PublishedContent == null)
            {
                throw new InvalidOperationException("There is no PublishedContent.");
            }

            var path = request.PublishedContent.Path;

            var publicAccessAttempt = _services.PublicAccessService.IsProtected(path);

            if (publicAccessAttempt)
            {
                _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Page is protected, check for access");

                var membershipHelper = Current.Factory.GetInstance <MembershipHelper>();

                if (membershipHelper.IsLoggedIn() == false)
                {
                    _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Not logged in, redirect to login page");

                    var loginPageId = publicAccessAttempt.Result.LoginNodeId;

                    if (loginPageId != request.PublishedContent.Id)
                    {
                        request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(loginPageId);
                    }
                }
                else if (_services.PublicAccessService.HasAccess(request.PublishedContent.Id, _services.ContentService, membershipHelper.CurrentUserName, membershipHelper.GetCurrentUserRoles()) == false)
                {
                    _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Current member has not access, redirect to error page");
                    var errorPageId = publicAccessAttempt.Result.NoAccessNodeId;
                    if (errorPageId != request.PublishedContent.Id)
                    {
                        request.PublishedContent = request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
                    }
                }
                else
                {
                    if (membershipHelper.IsUmbracoMembershipProviderActive())
                    {
                        // grab the current member
                        var member = membershipHelper.GetCurrentMember();
                        // if the member has the "approved" and/or "locked out" properties, make sure they're correctly set before allowing access
                        var memberIsActive = true;
                        if (member != null)
                        {
                            if (member.HasProperty(Constants.Conventions.Member.IsApproved) == false)
                            {
                                memberIsActive = member.Value <bool>(Constants.Conventions.Member.IsApproved);
                            }

                            if (member.HasProperty(Constants.Conventions.Member.IsLockedOut) == false)
                            {
                                memberIsActive = member.Value <bool>(Constants.Conventions.Member.IsLockedOut) == false;
                            }
                        }

                        if (memberIsActive == false)
                        {
                            _logger.Debug <PublishedRouter>(
                                "Current member is either unapproved or locked out, redirect to error page");
                            var errorPageId = publicAccessAttempt.Result.NoAccessNodeId;
                            if (errorPageId != request.PublishedContent.Id)
                            {
                                request.PublishedContent =
                                    request.UmbracoContext.PublishedSnapshot.Content.GetById(errorPageId);
                            }
                        }
                        else
                        {
                            _logger.Debug <PublishedRouter>("Current member has access");
                        }
                    }
                    else
                    {
                        _logger.Debug <PublishedRouter>("Current custom MembershipProvider member has access");
                    }
                }
            }
            else
            {
                _logger.Debug <PublishedRouter>("EnsurePublishedContentAccess: Page is not protected");
            }
        }
コード例 #21
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Follows internal redirections through the <c>umbracoInternalRedirectId</c> document property.
        /// </summary>
        /// <returns>A value indicating whether redirection took place and led to a new published document.</returns>
        /// <remarks>
        /// <para>Redirecting to a different site root and/or culture will not pick the new site root nor the new culture.</para>
        /// <para>As per legacy, if the redirect does not work, we just ignore it.</para>
        /// </remarks>
        private bool FollowInternalRedirects(PublishedRequest request)
        {
            if (request.PublishedContent == null)
            {
                throw new InvalidOperationException("There is no PublishedContent.");
            }

            // don't try to find a redirect if the property doesn't exist
            if (request.PublishedContent.HasProperty(Constants.Conventions.Content.InternalRedirectId) == false)
            {
                return(false);
            }

            var redirect = false;
            var valid    = false;
            IPublishedContent internalRedirectNode = null;
            var internalRedirectId = request.PublishedContent.Value(Constants.Conventions.Content.InternalRedirectId, defaultValue: -1);

            if (internalRedirectId > 0)
            {
                // try and get the redirect node from a legacy integer ID
                valid = true;
                internalRedirectNode = request.UmbracoContext.Content.GetById(internalRedirectId);
            }
            else
            {
                var udiInternalRedirectId = request.PublishedContent.Value <GuidUdi>(Constants.Conventions.Content.InternalRedirectId);
                if (udiInternalRedirectId != null)
                {
                    // try and get the redirect node from a UDI Guid
                    valid = true;
                    internalRedirectNode = request.UmbracoContext.Content.GetById(udiInternalRedirectId.Guid);
                }
            }

            if (valid == false)
            {
                // bad redirect - log and display the current page (legacy behavior)
                _logger.Debug <PublishedRouter>("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: value is not an int nor a GuidUdi.",
                                                request.PublishedContent.GetProperty(Constants.Conventions.Content.InternalRedirectId).GetSourceValue());
            }

            if (internalRedirectNode == null)
            {
                _logger.Debug <PublishedRouter>("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: no such published document.",
                                                request.PublishedContent.GetProperty(Constants.Conventions.Content.InternalRedirectId).GetSourceValue());
            }
            else if (internalRedirectId == request.PublishedContent.Id)
            {
                // redirect to self
                _logger.Debug <PublishedRouter>("FollowInternalRedirects: Redirecting to self, ignore");
            }
            else
            {
                request.SetInternalRedirectPublishedContent(internalRedirectNode); // don't use .PublishedContent here
                redirect = true;
                _logger.Debug <PublishedRouter>("FollowInternalRedirects: Redirecting to id={InternalRedirectId}", internalRedirectId);
            }

            return(redirect);
        }
コード例 #22
0
ファイル: PublishedRouter.cs プロジェクト: soreng/Umbraco-CMS
        /// <summary>
        /// Finds the site root (if any) matching the http request, and updates the PublishedRequest 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 = DomainUtilities.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);
        }
コード例 #23
0
        /// <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);
        }