@@ -25,7 +25,9 @@ public partial class WebHelper : IWebHelper
2525 private static bool ? s_optimizedCompilationsEnabled = null ;
2626 private static AspNetHostingPermissionLevel ? s_trustLevel = null ;
2727 private static readonly Regex s_staticExts = new Regex ( @"(.*?)\.(css|js|png|jpg|jpeg|gif|bmp|html|htm|xml|pdf|doc|xls|rar|zip|ico|eot|svg|ttf|woff|otf|axd|ashx|less)" , RegexOptions . Compiled | RegexOptions . IgnoreCase ) ;
28-
28+ private static readonly Regex s_htmlPathPattern = new Regex ( @"(?<=(?:href|src)=(?:""|'))(?!https?://)(?<url>[^(?:""|')]+)" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Multiline ) ;
29+ private static readonly Regex s_cssPathPattern = new Regex ( @"url\('(?<url>.+)'\)" , RegexOptions . IgnoreCase | RegexOptions . Compiled | RegexOptions . Multiline ) ;
30+
2931 private readonly HttpContextBase _httpContext ;
3032 private bool ? _isCurrentConnectionSecured ;
3133 private string _storeHost ;
@@ -690,6 +692,84 @@ public static AspNetHostingPermissionLevel GetTrustLevel()
690692 return s_trustLevel . Value ;
691693 }
692694
695+ /// <summary>
696+ /// Prepends protocol and host to all (relative) urls in a html string
697+ /// </summary>
698+ /// <param name="html">The html string</param>
699+ /// <param name="request">Request object</param>
700+ /// <returns>The transformed result html</returns>
701+ /// <remarks>
702+ /// All html attributed named <c>src</c> and <c>href</c> are affected, also occurences of <c>url('path')</c> within embedded stylesheets.
703+ /// </remarks>
704+ public static string MakeAllUrlsAbsolute ( string html , HttpRequestBase request )
705+ {
706+ Guard . ArgumentNotNull ( ( ) => request ) ;
707+
708+ if ( request . Url == null )
709+ {
710+ return html ;
711+ }
712+
713+ return MakeAllUrlsAbsolute ( html , request . Url . Scheme , request . Url . Authority ) ;
714+ }
715+
716+ /// <summary>
717+ /// Prepends protocol and host to all (relative) urls in a html string
718+ /// </summary>
719+ /// <param name="html">The html string</param>
720+ /// <param name="protocol">The protocol to prepend, e.g. <c>http</c></param>
721+ /// <param name="host">The host name to prepend, e.g. <c>www.mysite.com</c></param>
722+ /// <returns>The transformed result html</returns>
723+ /// <remarks>
724+ /// All html attributed named <c>src</c> and <c>href</c> are affected, also occurences of <c>url('path')</c> within embedded stylesheets.
725+ /// </remarks>
726+ public static string MakeAllUrlsAbsolute ( string html , string protocol , string host )
727+ {
728+ Guard . ArgumentNotEmpty ( ( ) => html ) ;
729+ Guard . ArgumentNotEmpty ( ( ) => protocol ) ;
730+ Guard . ArgumentNotEmpty ( ( ) => host ) ;
731+
732+ string baseUrl = string . Format ( "{0}://{1}" , protocol , host . TrimEnd ( '/' ) ) ;
733+
734+ MatchEvaluator evaluator = ( match ) =>
735+ {
736+ var url = match . Groups [ "url" ] . Value ;
737+ return "{0}{1}" . FormatCurrent ( baseUrl , url . EnsureStartsWith ( "/" ) ) ;
738+ } ;
739+
740+ html = s_htmlPathPattern . Replace ( html , evaluator ) ;
741+ html = s_cssPathPattern . Replace ( html , evaluator ) ;
742+
743+ return html ;
744+ }
745+
746+ /// <summary>
747+ /// Prepends protocol and host to the given (relative) url
748+ /// </summary>
749+ public static string GetAbsoluteUrl ( string url , HttpRequestBase request )
750+ {
751+ Guard . ArgumentNotEmpty ( ( ) => url ) ;
752+ Guard . ArgumentNotNull ( ( ) => request ) ;
753+
754+ if ( request . Url == null )
755+ {
756+ return url ;
757+ }
758+
759+ if ( url . StartsWith ( "http://" , StringComparison . OrdinalIgnoreCase ) || url . StartsWith ( "https://" , StringComparison . OrdinalIgnoreCase ) )
760+ {
761+ return url ;
762+ }
763+
764+ if ( url . StartsWith ( "~" ) )
765+ {
766+ url = VirtualPathUtility . ToAbsolute ( url ) ;
767+ }
768+
769+ url = String . Format ( "{0}://{1}{2}" , request . Url . Scheme , request . Url . Authority , url ) ;
770+ return url ;
771+ }
772+
693773 private class StoreHost
694774 {
695775 public string Host { get ; set ; }
0 commit comments