private void ProcessRequest(HttpContext context,
                                Uri requestUri,
                                bool useFriendlyUrls,
                                UrlAction result,
                                FriendlyUrlSettings settings,
                                bool allowSettingsChange,
                                Guid parentTraceId)
        {
            bool finished = false;
            bool showDebug = false;
            bool postRequest = false;

            HttpRequest request = context.Request;
            HttpResponse response = context.Response;
            string requestType = request.RequestType;
            NameValueCollection queryStringCol = request.QueryString;

            try
            {

                string fullUrl, querystring;
                //699: get the full url based on the request and the quersytring, rather than the requestUri.ToString()
                //there is a difference in encoding, which can corrupt results when an encoded value is in the querystring
                RewriteController.GetUrlWithQuerystring(request, requestUri, out fullUrl, out querystring);

                showDebug = CheckForDebug(request, queryStringCol, settings.AllowDebugCode);
                string ignoreRegex = settings.IgnoreRegex;
                bool ignoreRequest = IgnoreRequest(result, fullUrl, ignoreRegex, request);
                bool redirectAlias = false;
                if (!ignoreRequest)
                {
                    //set original path
                    context.Items["UrlRewrite:OriginalUrl"] = requestUri.AbsoluteUri;

                    //set the path of the result object, and determine if a redirect is allowed on this request
                    result.SetOriginalPath(requestUri.ToString(), settings);
                    //737 : set the mobile browser 
                    result.SetBrowserType(request, response, settings);
                    //add to context
                    context.Items["UrlRewrite:BrowserType"] = result.BrowserType.ToString();

                    //839 : split out this check
                    result.SetRedirectAllowed(result.OriginalPath, settings);

                    //find the portal alias first
                    string wrongAlias;
                    bool isPrimaryAlias;
                    var requestedAlias = GetPortalAlias(settings, fullUrl, out redirectAlias, out isPrimaryAlias, out wrongAlias);
                    
                    if (requestedAlias != null)
                    {
                        //827 : now get the correct settings for this portal (if not a test request)
                        //839 : separate out redirect check as well and move above first redirect test (ConfigurePortalAliasRedirect)
                        if (allowSettingsChange)
                        {
                            settings = new FriendlyUrlSettings(requestedAlias.PortalID);
                            result.SetRedirectAllowed(result.OriginalPath, settings);
                        }
                        result.PortalAlias = requestedAlias;
                        result.PrimaryAlias = requestedAlias;//this is the primary alias
                        result.PortalId = requestedAlias.PortalID;
                        result.CultureCode = requestedAlias.CultureCode;
                        //get the portal alias mapping for this portal
                        result.PortalAliasMapping = PortalSettings.GetPortalAliasMappingMode(requestedAlias.PortalID);

                        //if requested alias wasn't the primary, we have a replacement, redirects are allowed and the portal alias mapping mode is redirect
                        //then do a redirect based on the wrong portal
                        if ((redirectAlias && wrongAlias != null) && result.RedirectAllowed && result.PortalAliasMapping != PortalSettings.PortalAliasMapping.Redirect)
                        {
                            //this is the alias, we are going to enforce it as the primary alias
                            result.PortalAlias = requestedAlias;
                            result.PrimaryAlias = requestedAlias;
                            //going to redirect this alias because it is incorrect
                            //or do we just want to mark as 'check for 301??'
                            redirectAlias = ConfigurePortalAliasRedirect(ref result,
                                                                            wrongAlias,
                                                                            requestedAlias.HTTPAlias,
                                                                            false,
                                                                            settings.InternalAliasList,
                                                                            settings);
                        }
                        else
                        {
                            //do not redirect the wrong alias, but set the primary alias value
                            if (wrongAlias != null)
                            {
                                //get the portal alias info for the requested alias (which is the wrong one)
                                //and set that as the alias, but also set the found alias as the primary
                                PortalAliasInfo wrongAliasInfo = PortalAliasController.Instance.GetPortalAlias(wrongAlias);
                                if (wrongAliasInfo != null)
                                {
                                    result.PortalAlias = wrongAliasInfo;
                                    result.PrimaryAlias = requestedAlias;
                                }
                                
                            }
                        }
                    }
                }
                ignoreRegex = settings.IgnoreRegex;
                ignoreRequest = IgnoreRequest(result, fullUrl, ignoreRegex, request);
                if (!ignoreRequest) 
                {
                    //check to see if a post request
                    if (request.RequestType == "POST")
                    {
                        postRequest = true;
                    }

                    //check the portal alias again.  This time, in more depth now that the portal Id is known 
                    //this check handles browser types/language specific aliases & mobile aliases
                    string primaryHttpAlias;
                    if (!redirectAlias && IsPortalAliasIncorrect(context, request, requestUri, result, queryStringCol, settings, parentTraceId, out primaryHttpAlias))
                    {
                        //it was an incorrect alias
                        PortalAliasInfo primaryAlias = PortalAliasController.Instance.GetPortalAlias(primaryHttpAlias);
                        if (primaryAlias != null) result.PrimaryAlias = primaryAlias;
                        //try and redirect the alias if the settings allow it
                        redirectAlias = RedirectPortalAlias(primaryHttpAlias, ref result, settings);
                    }

                    if (redirectAlias)
                    {
                        //not correct alias for portal : will be redirected
                        //perform a 301 redirect if one has already been found
                        response.Status = "301 Moved Permanently";
                        response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                        response.AddHeader("Location", result.FinalUrl);
                        finished = true;
                        response.End();
                    }
                    if (!finished)
                    {
                        //Check to see if this to be rewritten into default.aspx?tabId=nn format
                        //this call is the main rewriting matching call.  It makes the decision on whether it is a 
                        //physical file, whether it is toe be rewritten or redirected by way of a stored rule

                        //Check if we have a standard url
                        var uri = new Uri(fullUrl);
                        if (uri.PathAndQuery.ToLowerInvariant().StartsWith("/" + Globals.glbDefaultPage.ToLowerInvariant()))
                        {
                            result.DoRewrite = true;
                            result.Action = ActionType.CheckFor301;
                            result.RewritePath = Globals.glbDefaultPage + uri.Query;
                        }
                        else
                        {
                            bool isPhysicalResource;
                            CheckForRewrite(fullUrl, querystring, result, useFriendlyUrls, queryStringCol, settings, out isPhysicalResource, parentTraceId);
                        }

                        //return 404 if there is no portal alias for a rewritten request
                        if (result.DoRewrite && result.PortalAlias == null)
                        {
                            //882 : move this logic in from where it was before to here
                            //so that non-rewritten requests don't trip over it
                            //no portal alias found for the request : that's a 404 error
                            result.Action = ActionType.Output404;
                            result.Reason = RedirectReason.No_Portal_Alias;

                            Handle404OrException(settings, context, null, result, false, showDebug);
                            finished = true; //cannot fulfil request unless correct portal alias specified
                        }
                    }

                    if (!finished && result.DoRewrite)
                    {
                        //check the identified portal alias details for any extra rewrite information required
                        //this includes the culture and the skin, which can be placed into the rewrite path
                        //This logic is here because it will catch any Urls which are excluded from rewriting
                        var primaryAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(result.PortalId).ToList();

                        if (result.PortalId > -1 && result.HttpAlias != null)
                        {
                            string culture;
                            string skin;
                            BrowserTypes browserType;
                            primaryAliases.GetSettingsByPortalIdAndAlias(result.PortalId, result.HttpAlias,
                                                                                            out culture, 
                                                                                            out browserType,
                                                                                            out skin);
                            //add language code to path if it exists (not null) and if it's not already there
                            string rewritePath = result.RewritePath;
                            if (RewriteController.AddLanguageCodeToRewritePath(ref rewritePath, culture))
                            {
                                result.CultureCode = culture;
                            }

                            //852: add skinSrc to path if it exists and if it's not already there
                            string debugMessage;
                            RewriteController.AddSkinToRewritePath(result.TabId, result.PortalId, ref rewritePath, skin, out debugMessage);
                            result.RewritePath = rewritePath; //reset back from ref temp var
                            if (debugMessage != null)
                            {
                                result.DebugMessages.Add(debugMessage);
                            }
                        }
                    }

                    if (!finished && result.DoRewrite)
                    {
                        //if so, do the rewrite
                        if (result.RewritePath.StartsWith(result.Scheme) || result.RewritePath.StartsWith(Globals.glbDefaultPage) == false)
                        {
                            if (result.RewritePath.Contains(Globals.glbDefaultPage) == false)
                            {
                                RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath);
                            }
                            else
                            {
                                //if there is no TabId and we have the domain
                                if (!result.RewritePath.ToLowerInvariant().Contains("tabId="))
                                {
                                    RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath);
                                }
                                else
                                {
                                    RewriterUtils.RewriteUrl(context, result.RewritePath);
                                }
                            }
                        }
                        else
                        {
                            RewriterUtils.RewriteUrl(context, "~/" + result.RewritePath);
                        }
                    }

                    //confirm which portal the request is for 
                    if (!finished)
                    {
                        IdentifyPortalAlias(context, request, requestUri, result, queryStringCol, settings, parentTraceId);
                        if (result.Action == ActionType.Redirect302Now)
                        {
                            //performs a 302 redirect if requested
                            response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                            response.Redirect(result.FinalUrl, false);
                            finished = true;
                        }
                        else
                        {
                            if (result.Action == ActionType.Redirect301 && !string.IsNullOrEmpty(result.FinalUrl))
                            {
                                finished = true;
                                //perform a 301 redirect if one has already been found
                                response.Status = "301 Moved Permanently";
                                response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                response.AddHeader("Location", result.FinalUrl);
                                response.End();
                            }
                        }
                    }
                    
                    if (!finished)
                    {
                        //check to see if this tab has an external url that should be forwared or not
                        finished = CheckForTabExternalForwardOrRedirect(context, ref result, response, settings, parentTraceId);
                    }

                    //check for a parameter redirect (we had to do all the previous processing to know we are on the right portal and identify the tabid)
                    //if the CustomParmRewrite flag is set, it means we already rewrote these parameters, so they have to be correct, and aren't subject to 
                    //redirection.  The only reason to do a custom parm rewrite is to interpret already-friendly parameters
                    if (!finished
                        && !postRequest /* either request is null, or it's not a post - 551 */
                        && result.HttpAlias != null /* must have a http alias */
                        && !result.CustomParmRewrite && /* not custom rewritten parms */
                        ((settings.EnableCustomProviders &&
                          RedirectController.CheckForModuleProviderRedirect(requestUri, ref result, queryStringCol, settings, parentTraceId))
                        //894 : allow disable of all custom providers
                         ||
                         RedirectController.CheckForParameterRedirect(requestUri, ref result, queryStringCol, settings)))
                    {
                        //301 redirect to new location based on parameter match
                        if (response != null)
                        {
                            switch (result.Action)
                            {
                                case ActionType.Redirect301:
                                    response.Status = "301 Moved Permanently";
                                    response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                    response.AddHeader("Location", result.FinalUrl);
                                    response.End();
                                    break;
                                case ActionType.Redirect302:
                                    response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                    response.Redirect(result.FinalUrl);
                                    break;
                                case ActionType.Output404:
                                    response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " "));
                                    Handle404OrException(settings, context, null, result, true, showDebug);
                                    break;
                            }
                        }
                        finished = true;
                    }

                    //shifted until after the 301 redirect code to allow redirects to be checked for pages which have no rewrite value
                    //look for a 404 result from the rewrite, because of a deleted page or rule
                    if (!finished && result.Action == ActionType.Output404)
                    {
                        if (result.OriginalPath == result.HttpAlias && result.PortalAlias != null
                                && result.Reason != RedirectReason.Deleted_Page && result.Reason != RedirectReason.Disabled_Page)
                        {
                            //Request for domain with no page identified (and no home page set in Site Settings)
                            result.Action = ActionType.Continue;
                        }
                        else
                        {
                            finished = true;
                            response.AppendHeader("X-Result-Reason", result.Reason.ToString().Replace("_", " "));

                            if (showDebug)
                            {
                                ShowDebugData(context, requestUri.AbsoluteUri, result, null);
                            }
                            //show the 404 page if configured
                            result.Reason = RedirectReason.Requested_404;
                            Handle404OrException(settings, context, null, result, true, showDebug);
                        }
                    }

                    if (!finished)
                    {
                        //add the portal settings to the app context if the portal alias has been found and is correct
                        if (result.PortalId != -1 && result.PortalAlias != null)
                        {
                            Globals.SetApplicationName(result.PortalId);
                            // load the PortalSettings into current context 
                            var portalSettings = new PortalSettings(result.TabId, result.PortalAlias);
                            //set the primary alias if one was specified
                            if (result.PrimaryAlias != null) portalSettings.PrimaryAlias = result.PrimaryAlias;

                            if (result.CultureCode != null && fullUrl.Contains(result.CultureCode) &&
                                portalSettings.DefaultLanguage == result.CultureCode)
                            {
                                //when the request culture code is the same as the portal default, check for a 301 redirect, because we try and remove the language from the url where possible
                                result.Action = ActionType.CheckFor301;
                            }

                            int portalHomeTabId = portalSettings.HomeTabId;
                            if (context != null && portalSettings != null && !context.Items.Contains("PortalSettings"))
                            {
                                context.Items.Add("PortalSettings", portalSettings);
                            }
                            //check if a secure redirection is needed
                            //this would be done earlier in the piece, but need to know the portal settings, tabid etc before processing it
                            bool redirectSecure = CheckForSecureRedirect(portalSettings, requestUri, result, queryStringCol, settings);
                            if (redirectSecure)
                            {
                                if (response != null)
                                {
                                    //702 : don't check final url until checked for null reference first
                                    if (result.FinalUrl != null)
                                    {
                                        if (result.FinalUrl.StartsWith("https://"))
                                        {
                                            if (showDebug)
                                            {
                                                /*
                                                string debugMsg = "{0}, {1}, {2}, {3}, {4}";
                                                string productVer = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version.ToString();
                                                response.AppendHeader("X-" + prodName + "-Debug", string.Format(debugMsg, requestUri.AbsoluteUri, result.FinalUrl, result.RewritePath, result.Action, productVer));
                                                 */
                                                ShowDebugData(context, fullUrl, result, null);
                                            }
                                            response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                            response.Redirect(result.FinalUrl, false);
                                            finished = true;
                                        }
                                        else
                                        {
                                            if (settings.SSLClientRedirect)
                                            {
                                                //redirect back to http version, use client redirect
                                                response.Clear();
                                                // add a refresh header to the response 
                                                response.AddHeader("Refresh", "0;URL=" + result.FinalUrl);
                                                // add the clientside javascript redirection script
                                                response.Write("<html><head><title></title>");
                                                response.Write(@"<!-- <script language=""javascript"">window.location.replace(""" + result.FinalUrl + @""")</script> -->");
                                                response.Write("</head><body><div><a href='" + result.FinalUrl + "'>" + result.FinalUrl + "</a></div></body></html>");
                                                if (showDebug)
                                                {
                                                    /*
                                                    string debugMsg = "{0}, {1}, {2}, {3}, {4}";
                                                    string productVer = System.Reflection.Assembly.GetExecutingAssembly().GetName(false).Version.ToString();
                                                    response.AppendHeader("X-" + prodName + "-Debug", string.Format(debugMsg, requestUri.AbsoluteUri, result.FinalUrl, result.RewritePath, result.Action, productVer));
                                                     */
                                                    ShowDebugData(context, fullUrl, result, null);
                                                }
                                                // send the response
                                                //891 : reinstate the response.end to stop the entire page loading
                                                response.End();
                                                finished = true;
                                            }
                                            else
                                            {
                                                response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                                response.Redirect(result.FinalUrl, false);
                                                finished = true;
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                //check for, and do a 301 redirect if required 
                                if (CheckForRedirects(requestUri, fullUrl, queryStringCol, result, requestType, settings, portalHomeTabId))
                                {
                                    if (response != null)
                                    {
                                        if (result.Action == ActionType.Redirect301)
                                        {
                                            response.Status = "301 Moved Permanently";
                                            response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                            response.AddHeader("Location", result.FinalUrl);
                                            finished = true;
                                            response.End();
                                        }
                                        else if (result.Action == ActionType.Redirect302)
                                        {
                                            response.AppendHeader("X-Redirect-Reason", result.Reason.ToString().Replace("_", " ") + " Requested");
                                            response.Redirect(result.FinalUrl, false);
                                            finished = true;
                                        }
                                    }
                                }
                                else
                                {
                                    //612 : Don't clear out a 302 redirect if set
                                    if (result.Action != ActionType.Redirect302 &&
                                        result.Action != ActionType.Redirect302Now)
                                    {
                                        result.Reason = RedirectReason.Not_Redirected;
                                        result.FinalUrl = null;
                                    }
                                }
                            }
                        }
                        else
                        {
                            // alias does not exist in database 
                            // and all attempts to find another have failed 
                            //this should only happen if the HostPortal does not have any aliases 
                            result.Action = ActionType.Output404;
                            if (response != null)
                            {
                                if (showDebug)
                                {
                                    ShowDebugData(context, fullUrl, result, null);
                                }
                                result.Reason = RedirectReason.Requested_404;
                                //912 : change 404 type to transfer to allow transfer to main portal in single-portal installs
                                Handle404OrException(settings, context, null, result, true, showDebug);
                                finished = true;
                            }
                        }
                    }

                    //404 page ??
                    if (settings.TabId404 > 0 && settings.TabId404 == result.TabId)
                    {
                        string status = queryStringCol["status"];
                        if (status == "404")
                        {
                            //respond with a 404 error
                            result.Action = ActionType.Output404;
                            result.Reason = RedirectReason.Requested_404_In_Url;
                            Handle404OrException(settings, context, null, result, true, showDebug);
                        }
                    }
                    else
                    {
                        if (result.DoRewrite == false && result.CanRewrite != StateBoolean.False && !finished &&
                            result.Action == ActionType.Continue)
                        {
                            //739 : catch no-extension 404 errors
                            string pathWithNoQs = result.OriginalPath;
                            if (pathWithNoQs.Contains("?"))
                            {
                                pathWithNoQs = pathWithNoQs.Substring(0, pathWithNoQs.IndexOf("?", StringComparison.Ordinal));
                            }
                            if (!pathWithNoQs.Substring(pathWithNoQs.Length - 5, 5).Contains("."))
                            {
                                //no page extension, output a 404 if the Url is not found
                                //766 : check for physical path before passing off as a 404 error
                                //829 : change to use action physical path
                                //893 : filter by regex pattern to exclude urls which are valid, but show up as extensionless
                                if ((request != null && Directory.Exists(result.PhysicalPath))
                                    ||
                                    Regex.IsMatch(pathWithNoQs, settings.ValidExtensionlessUrlsRegex, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
                                {
                                    //do nothing : it's a request for a valid physical path, maybe including a default document
                                    result.VirtualPath = StateBoolean.False;
                                }
                                else
                                {
                                    if (!ServiceApi.IsMatch(context.Request.RawUrl))
                                    {
                                        //no physical path, intercept the request and hand out a 404 error
                                        result.Action = ActionType.Output404;
                                        result.Reason = RedirectReason.Page_404;
                                        result.VirtualPath = StateBoolean.True;
                                        //add in a message to explain this 404, becaue it can be cryptic
                                        result.DebugMessages.Add("404 Reason : Not found and no extension");
                                        Handle404OrException(settings, context, null, result, true, showDebug);
                                    }
                                }
                            }
                        }
                    }

                    //  show debug messages after extensionless-url special 404 handling
                    if (showDebug)
                    {
                        ShowDebugData(context, fullUrl, result, null);
                    }
                }
            }
            catch (ThreadAbortException)
            {
                //do nothing, a threadAbortException will have occured from using a server.transfer or response.redirect within the code block.  This is the highest
                //level try/catch block, so we handle it here.
            }
            catch (Exception ex)
            {
                if (showDebug)
                {
                    Services.Exceptions.Exceptions.LogException(ex);
                }
                if (response != null)
                {
                    if (showDebug)
                    {
                        ShowDebugData(context, requestUri.AbsoluteUri, result, ex);
                    }
                    if (result != null)
                    {
                        result.Ex = ex;
                        result.Reason = RedirectReason.Exception;
                    }
                    Handle404OrException(settings, context, ex, result, false, showDebug);
                }
                else
                {
                    if (result != null && result.DebugMessages != null)
                    {
                        result.DebugMessages.Add("Exception: " + ex.Message);
                        result.DebugMessages.Add("Stack Trace: " + ex.StackTrace);
                    }
                    throw;
                }
            }
            finally
            {
                //809 : add in new code copied from urlRewrite class in standard Url Rewrite module
                if (context != null && context.Items["FirstRequest"] != null)
                {
                    context.Items.Remove("FirstRequest");
                    //process any messages in the eventQueue for the Application_Start_FIrstRequest event
                    EventQueueController.ProcessMessages("Application_Start_FirstRequest");
                }
            }
        }
 private bool IsRedirectAllowed(string url, HttpApplication app, PortalSettings portalSettings)
 {
     var urlAction = new UrlAction(app.Request);
     urlAction.SetRedirectAllowed(url, new FriendlyUrlSettings(portalSettings.PortalId));
     return urlAction.RedirectAllowed;
 }