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; }