Having built a blogging engine into my proprietary content management system at work, one thing I have to deal with in terms of the blog is making sure that any blog posts with references to website content make use of a fully-qualified, absolute URLs when they are rendered in the RSS feed.
Here’s two extension methods that will convert relative URLs into absolute URLs which include the full host name and port (if applicable). The first method will take a single app-relative URL (~/path/to/foo) and fully-qualify it, while the second method accepts a block of HTML and uses regular expressions to match HTML attributes which contain root-relative URLs (/path/to/foo) and replaces them using the first method.
/// <summary>
/// Converts the provided app-relative path into an absolute Url containing the full host name
/// </summary>
/// <param name="relativeUrl">App-Relative path</param>
/// <returns>Provided relativeUrl parameter as fully qualified Url</returns>
/// <example>~/path/to/foo to http://www.web.com/path/to/foo</example>
public static string ToAbsoluteUrl(this string relativeUrl) {
if (string.IsNullOrEmpty(relativeUrl))
return relativeUrl;
if (HttpContext.Current == null)
return relativeUrl;
if (relativeUrl.StartsWith("/"))
relativeUrl = relativeUrl.Insert(0, "~");
if (!relativeUrl.StartsWith("~/"))
relativeUrl = relativeUrl.Insert(0, "~/");
var url = HttpContext.Current.Request.Url;
var port = url.Port != 80 ? (":" + url.Port) : String.Empty;
return String.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(relativeUrl));
}
/// <summary>
/// Converts all root-relatives Urls within the provided HTML string to absolute Urls
/// </summary>
/// <returns>Provided HTML parameter with fully qualified Urls substituted</returns>
/// <example>href="/path/to/foo.jpg" to href="http://www.web.com/path/to/foo.jpg"</example>
/// <example>@import url(/path/to/foo) to @import url(http://www.web.com/path/to/foo)</example>
public static string HtmlAppRelativeUrlsToAbsoluteUrls(this string html) {
if (String.IsNullOrEmpty(html))
return html;
const string htmlPattern = "(?<attrib>\\shref|\\ssrc|\\sbackground)\\s*?=\\s*?"
+ "(?<delim1>[\"'\\\\]{0,2})(?!#|http|ftp|mailto|javascript)"
+ "/(?<url>[^\"'>\\\\]+)(?<delim2>[\"'\\\\]{0,2})";
Regex htmlRegex = new Regex(htmlPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
html = htmlRegex.Replace(html, m => htmlRegex.Replace(m.Value, "${attrib}=${delim1}" + ("~/" + m.Groups["url"].Value).ToAbsoluteUrl() + "${delim2}"));
const string cssPattern = "@import\\s+?(url)*['\"(]{1,2}"
+ "(?!http)\\s*/(?<url>[^\"')]+)['\")]{1,2}";
Regex cssRegex = new Regex(cssPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
html = cssRegex.Replace(html, m => cssRegex.Replace(m.Value, "@import url(" + ("~/" + m.Groups["url"].Value).ToAbsoluteUrl() + ")"));
return html;
}
Sources
- Thanks to Jeff Atwood for the awesome regular expressions that are the magic behind this code.
0 comments:
Post a Comment