PageRenderTime 84ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Web/Components/UrlRewriter.cs

#
C# | 382 lines | 252 code | 81 blank | 49 comment | 58 complexity | 029b92a4d4f5e1b9ad382442c49ec533 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause, CPL-1.0, CC-BY-SA-3.0, GPL-2.0
  1. // Author: Joe Audette
  2. // Created: 2005-06-01
  3. // Last Modified: 2011-11-18
  4. //
  5. // The use and distribution terms for this software are covered by the
  6. // Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
  7. // which can be found in the file CPL.TXT at the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by
  9. // the terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. using System;
  13. using System.Data;
  14. using System.Text;
  15. using System.Web;
  16. using log4net;
  17. using mojoPortal.Business;
  18. using mojoPortal.Business.WebHelpers;
  19. using mojoPortal.Web.Framework;
  20. namespace mojoPortal.Web
  21. {
  22. public class UrlRewriter : IHttpModule
  23. {
  24. private static readonly ILog log = LogManager.GetLogger(typeof(UrlRewriter));
  25. private static bool debugLog = log.IsDebugEnabled;
  26. public void Init(HttpApplication app)
  27. {
  28. app.BeginRequest += new EventHandler(this.UrlRewriter_BeginRequest);
  29. }
  30. public void Dispose() {}
  31. protected void UrlRewriter_BeginRequest(object sender, EventArgs e)
  32. {
  33. if (sender == null) return;
  34. HttpApplication app = (HttpApplication)sender;
  35. if (!WebConfigSettings.UseUrlReWritingForStaticFiles)
  36. {
  37. if (WebUtils.IsRequestForStaticFile(app.Request.Path)) { return; }
  38. if (
  39. (app.Request.Path.EndsWith("csshandler.ashx", StringComparison.InvariantCultureIgnoreCase))
  40. || (app.Request.Path.EndsWith("CaptchaImage.ashx", StringComparison.InvariantCultureIgnoreCase))
  41. || (app.Request.Path.EndsWith("/Data/", StringComparison.InvariantCultureIgnoreCase))
  42. || (app.Request.Path.StartsWith("/Data/", StringComparison.InvariantCultureIgnoreCase))
  43. )
  44. {
  45. return;
  46. }
  47. }
  48. if (WebConfigSettings.UseUrlReWriting)
  49. {
  50. try
  51. {
  52. RewriteUrl(app);
  53. }
  54. catch (InvalidOperationException ex)
  55. {
  56. log.Error(ex);
  57. }
  58. catch (System.Data.Common.DbException ex)
  59. {
  60. log.Error(ex);
  61. }
  62. catch (Exception ex)
  63. {
  64. // hate to trap System.Exception but SqlCeException doe snot inherit from DbException as it should
  65. if (DatabaseHelper.DBPlatform() != "SqlCe") { throw ex; }
  66. log.Error(ex);
  67. }
  68. }
  69. }
  70. private static void RewriteUrl(HttpApplication app)
  71. {
  72. if (app == null) return;
  73. string requestPath = app.Request.Path;
  74. bool useFolderForSiteDetection = WebConfigSettings.UseFoldersInsteadOfHostnamesForMultipleSites;
  75. string virtualFolderName;
  76. if (useFolderForSiteDetection)
  77. {
  78. virtualFolderName = VirtualFolderEvaluator.VirtualFolderName();
  79. }
  80. else
  81. {
  82. virtualFolderName = string.Empty;
  83. }
  84. bool setClientFilePath = true;
  85. if (
  86. (useFolderForSiteDetection)
  87. && (virtualFolderName.Length > 0)
  88. )
  89. {
  90. setClientFilePath = false;
  91. // requesting root of folderbased site like /folder1/
  92. // don't re-write it
  93. if (requestPath.EndsWith(virtualFolderName + "/"))
  94. {
  95. return;
  96. }
  97. }
  98. // Remove extended information after path, such as for Web services
  99. // or bogus /default.aspx/default.aspx
  100. string pathInfo = app.Request.PathInfo;
  101. if (pathInfo != string.Empty)
  102. {
  103. requestPath = requestPath.Substring(0, requestPath.Length - pathInfo.Length);
  104. }
  105. // 2006-01-25 : David Neal : Updated URL checking, Fixes for sites where mojoPortal
  106. // is running at the root and for bogus default document URLs
  107. // Get the relative target URL without the application root
  108. string appRoot = WebUtils.GetApplicationRoot();
  109. if (requestPath.Length == appRoot.Length) { return; }
  110. string targetUrl = requestPath.Substring(appRoot.Length + 1);
  111. //if (targetUrl.Length == 0) return;
  112. if(StringHelper.IsCaseInsensitiveMatch(targetUrl, "default.aspx"))return;
  113. if (useFolderForSiteDetection)
  114. {
  115. if (targetUrl.StartsWith(virtualFolderName + "/"))
  116. {
  117. // 2009-03-01 Kris reported a bug where folder site using /er for the folder
  118. // was making an incorrect targetUrl
  119. // this url from an edit link in feed manager http://localhost/er/FeedManager/FeedEdit.aspx?mid=54&pageid=34
  120. // was getting changed to http://localhost/er/FeedManagFeedEdit.aspx?mid=54&pageid=34 causig a 404
  121. // caused by this commented line
  122. //targetUrl = targetUrl.Replace(virtualFolderName + "/", string.Empty);
  123. //fixed by changing to this
  124. targetUrl = targetUrl.Remove(0, virtualFolderName.Length + 1);
  125. }
  126. }
  127. if (!WebConfigSettings.Disable301Redirector)
  128. {
  129. try
  130. {
  131. // check if the requested url is supposed to redirect
  132. string redirectUrl = GetRedirectUrl(targetUrl);
  133. if (redirectUrl.Length > 0)
  134. {
  135. Do301Redirect(app, redirectUrl);
  136. return;
  137. }
  138. }
  139. catch (NullReferenceException ex)
  140. {
  141. // this can happen on a new installation so we catch and log it
  142. log.Error(ex);
  143. }
  144. }
  145. FriendlyUrl friendlyUrl = null;
  146. SiteSettings siteSettings = CacheHelper.GetCurrentSiteSettings();
  147. //this will happen on a new installation
  148. if (siteSettings == null) { return; }
  149. if (
  150. (useFolderForSiteDetection)
  151. && (virtualFolderName.Length > 0)
  152. )
  153. {
  154. //int siteID = SiteSettings.GetSiteIDFromFolderName(virtualFolderName);
  155. friendlyUrl = new FriendlyUrl(siteSettings.SiteId, targetUrl);
  156. }
  157. else
  158. {
  159. if (siteSettings.DefaultFriendlyUrlPattern == SiteSettings.FriendlyUrlPattern.PageName)
  160. {
  161. //when using extensionless urls we consistently store them without a trailing slash
  162. if (targetUrl.EndsWith("/"))
  163. {
  164. targetUrl = targetUrl.Substring(0, targetUrl.Length - 1);
  165. setClientFilePath = false;
  166. }
  167. }
  168. if (WebConfigSettings.AlwaysUrlEncode)
  169. {
  170. friendlyUrl = new FriendlyUrl(WebUtils.GetHostName(), HttpUtility.UrlEncode(targetUrl));
  171. //in case existing pages are not url encoded since this setting was added 2009-11-15, try again without encoding
  172. if (!friendlyUrl.FoundFriendlyUrl)
  173. {
  174. if (WebConfigSettings.RetryUnencodedOnUrlNotFound)
  175. {
  176. friendlyUrl = new FriendlyUrl(WebUtils.GetHostName(), targetUrl);
  177. }
  178. }
  179. }
  180. else
  181. {
  182. friendlyUrl = new FriendlyUrl(WebUtils.GetHostName(), targetUrl);
  183. }
  184. }
  185. if (
  186. (friendlyUrl == null)
  187. ||(!friendlyUrl.FoundFriendlyUrl)
  188. )
  189. {
  190. if (
  191. (useFolderForSiteDetection)
  192. && (virtualFolderName.Length > 0)
  193. )
  194. {
  195. SiteUtils.TrackUrlRewrite();
  196. //2009-03-01 same bug as above
  197. //string pathToUse = requestPath.Replace(virtualFolderName + "/", string.Empty);
  198. string pathToUse = requestPath.Remove(0, virtualFolderName.Length + 1);
  199. // this is a flag that can be used to detect if the url was already rewritten if you need to run a custom url rewriter after this one
  200. // you should only rewrite urls that were not rewritten by mojoPortal url rewriter
  201. app.Context.Items["mojoPortaLDidRewriteUrl"] = true;
  202. app.Context.RewritePath(
  203. pathToUse,
  204. string.Empty,
  205. app.Request.QueryString.ToString(),
  206. setClientFilePath);
  207. }
  208. else
  209. {
  210. if ((targetUrl.Length > 1)&&(!targetUrl.Contains(".")))
  211. {
  212. // this is a flag that will be detected in our pagenotfoundhttpmodule
  213. // so we can handle 404 for extensionless urls
  214. app.Context.Items["UrlNotFound"] = true;
  215. }
  216. return;
  217. }
  218. }
  219. string queryStringToUse = string.Empty;
  220. string realPageName = string.Empty;
  221. if (friendlyUrl.RealUrl.IndexOf('?') > 0)
  222. {
  223. realPageName = friendlyUrl.RealUrl.Substring(0, friendlyUrl.RealUrl.IndexOf('?'));
  224. queryStringToUse = friendlyUrl.RealUrl.Substring(friendlyUrl.RealUrl.IndexOf('?') + 1);
  225. }
  226. else // Added by Christian Fredh 10/30/2006
  227. {
  228. realPageName = friendlyUrl.RealUrl;
  229. }
  230. if (debugLog) { log.Debug("Rewriting URL to " + friendlyUrl.RealUrl); }
  231. if ((realPageName != null) && (!String.IsNullOrEmpty(realPageName)))
  232. {
  233. if (queryStringToUse == null)
  234. {
  235. queryStringToUse = String.Empty;
  236. }
  237. StringBuilder originalQueryString = new StringBuilder();
  238. // get any additional params besides pageid
  239. string separator = string.Empty;
  240. foreach (string key in app.Request.QueryString.AllKeys)
  241. {
  242. if (key != "pageid")
  243. {
  244. originalQueryString.Append( separator + key + "="
  245. + app.Request.QueryString.Get(key));
  246. if(separator.Length == 0)separator = "&";
  247. }
  248. }
  249. if (originalQueryString.Length > 0)
  250. {
  251. if (queryStringToUse.Length == 0)
  252. {
  253. queryStringToUse = originalQueryString.ToString();
  254. }
  255. else
  256. {
  257. queryStringToUse += "&" + originalQueryString.ToString();
  258. }
  259. }
  260. SiteUtils.TrackUrlRewrite();
  261. //log.Info("re-writing to " + realPageName);
  262. // this is a flag that can be used to detect if the url was already rewritten if you need to run a custom url rewriter after this one
  263. // you should only rewrite urls that were not rewritten by mojoPortal url rewriter
  264. app.Context.Items["mojoPortaLDidRewriteUrl"] = true;
  265. app.Context.RewritePath(realPageName, string.Empty, queryStringToUse, setClientFilePath);
  266. }
  267. }
  268. /// <summary>
  269. /// note the expected targetUrl and returned url are not fully qualified, but relative without a /
  270. /// </summary>
  271. /// <param name="targetUrl"></param>
  272. /// <returns></returns>
  273. private static string GetRedirectUrl(string targetUrl)
  274. {
  275. //lookup if this url is to be redirected, if found return the new url
  276. string newUrl = string.Empty;
  277. SiteSettings siteSettings = CacheHelper.GetCurrentSiteSettings();
  278. using (IDataReader reader = RedirectInfo.GetBySiteAndUrl(siteSettings.SiteId, targetUrl))
  279. {
  280. if (reader.Read())
  281. {
  282. newUrl = reader["NewUrl"].ToString();
  283. }
  284. }
  285. return newUrl;
  286. }
  287. private static void Do301Redirect(HttpApplication app, string newUrl)
  288. {
  289. string siteRoot = SiteUtils.GetNavigationSiteRoot();
  290. app.Context.Response.Status = "301 Moved Permanently";
  291. if (WebConfigSettings.PassQueryStringFor301Redirects)
  292. {
  293. app.Context.Response.AddHeader("Location", siteRoot + "/" + newUrl + app.Request.Url.Query);
  294. }
  295. else
  296. {
  297. app.Context.Response.AddHeader("Location", siteRoot + "/" + newUrl);
  298. }
  299. }
  300. }
  301. }