using System; using System.Collections.Generic; using System.IO; using System.Web; using System.Text; namespace ScrewTurn.Wiki { /// /// Implements useful URL-handling tools. /// public static class UrlTools { /// /// Properly routes the current virtual request to a physical ASP.NET page. /// public static void RouteCurrentRequest() { // Extract the physical page name, e.g. MainPage, Edit or Category string pageName = Path.GetFileNameWithoutExtension(HttpContext.Current.Request.PhysicalPath); // Exctract the extension, e.g. .ashx or .aspx string ext = Path.GetExtension(HttpContext.Current.Request.PhysicalPath).ToLowerInvariant(); // Remove trailing dot, .ashx -> ashx if(ext.Length > 0) ext = ext.Substring(1); // IIS7+Integrated Pipeline handles all requests through the ASP.NET engine // All non-interesting files are not processed, such as GIF, CSS, etc. if(ext != "ashx" && ext != "aspx") return; // Extract the current namespace, if any string nspace = GetCurrentNamespace() + ""; if(!string.IsNullOrEmpty(nspace)) pageName = pageName.Substring(nspace.Length + 1); // Trim Namespace. from pageName string queryString = ""; // Empty or begins with ampersand, not question mark try { // This might throw exceptions if 3rd-party modules interfer with the request pipeline queryString = HttpContext.Current.Request.Url.Query.Replace("?", "&"); } catch { } if(ext.Equals("ashx")) { // Content page requested, process it via Default.aspx if(!queryString.Contains("NS=")) { HttpContext.Current.RewritePath("~/Default.aspx?Page=" + Tools.UrlEncode(pageName) + "&NS=" + Tools.UrlEncode(nspace) + queryString); } else { HttpContext.Current.RewritePath("~/Default.aspx?Page=" + Tools.UrlEncode(pageName) + queryString); } } else if(ext.Equals("aspx")) { // System page requested, redirect to the root of the application // For example: http://www.server.com/Namespace.Edit.aspx?Page=MainPage -> http://www.server.com/Edit.aspx?Page=MainPage&NS=Namespace if(!string.IsNullOrEmpty(nspace)) { if(!queryString.Contains("NS=")) { HttpContext.Current.RewritePath("~/" + Tools.UrlEncode(pageName) + "." + ext + "?NS=" + Tools.UrlEncode(nspace) + queryString); } else { if(queryString.Length > 1) queryString = "?" + queryString.Substring(1); HttpContext.Current.RewritePath("~/" + Tools.UrlEncode(pageName) + "." + ext + queryString); } } } // else nothing to do } /// /// Extracts the current namespace from the URL, such as /App/Namespace.Edit.aspx. /// /// The current namespace, or an empty string. null if the URL format is not specified. public static string GetCurrentNamespace() { string filename = Path.GetFileNameWithoutExtension(HttpContext.Current.Request.Path); // e.g. MainPage or Edit or Namespace.MainPage or Namespace.Edit // Use dot to split the filename string[] fields = filename.Split('.'); if(fields.Length != 1 && fields.Length != 2) return null; // Unrecognized format if(fields.Length == 1) return ""; // Just page name else return fields[0]; // Namespace.Page } /// /// Redirects the current response to the specified URL, properly appending the current namespace if any. /// /// The target URL. public static void Redirect(string target) { Redirect(target, true); } /// /// Redirects the current response to the specified URL, appending the current namespace if requested. /// /// The target URL. /// A value indicating whether to add the namespace. public static void Redirect(string target, bool addNamespace) { string nspace = HttpContext.Current.Request["NS"]; if(nspace == null || nspace.Length == 0 || !addNamespace) HttpContext.Current.Response.Redirect(target); else HttpContext.Current.Response.Redirect(target + (target.Contains("?") ? "&" : "?") + "NS=" + Tools.UrlEncode(nspace)); } /// /// Builds a URL properly prepending the namespace to the URL. /// /// The chunks used to build the URL. /// The complete URL. public static string BuildUrl(params string[] chunks) { if(chunks == null) throw new ArgumentNullException("chunks"); if(chunks.Length == 0) return ""; // Shortcut StringBuilder temp = new StringBuilder(chunks.Length * 10); foreach(string chunk in chunks) { temp.Append(chunk); } string tempString = temp.ToString(); if(tempString.StartsWith("++")) return tempString.Substring(2); string nspace = HttpContext.Current.Request["NS"]; if(string.IsNullOrEmpty(nspace)) nspace = null; if(nspace == null) nspace = GetCurrentNamespace(); if(string.IsNullOrEmpty(nspace)) nspace = null; else nspace = Pages.FindNamespace(nspace).Name; if(nspace != null) { string tempStringLower = tempString.ToLowerInvariant(); if((tempStringLower.Contains(".ashx") || tempStringLower.Contains(".aspx")) && !tempString.StartsWith(Tools.UrlEncode(nspace) + ".")) temp.Insert(0, nspace + "."); } return temp.ToString(); } /// /// Builds a URL properly appendind the NS parameter if appropriate. /// /// The destination . /// The chunks to append. public static void BuildUrl(StringBuilder destination, params string[] chunks) { if(destination == null) throw new ArgumentNullException("destination"); destination.Append(BuildUrl(chunks)); } /// /// Redirects to the default page of the current namespace. /// public static void RedirectHome() { Redirect(BuildUrl(Settings.DefaultPage, Settings.PageExtension)); } } }