using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Text; using System.Web; using System.Web.Hosting; namespace PalGain.Core { /// /// Represents a common helper /// public partial class WebHelper : IWebHelper { #region Fields private readonly HttpContextBase _httpContext; #endregion #region Utilities protected virtual Boolean IsRequestAvailable(HttpContextBase httpContext) { if (httpContext == null) return false; try { if (httpContext.Request == null) return false; } catch (HttpException) { return false; } return true; } protected virtual bool TryWriteWebConfig() { try { // In medium trust, "UnloadAppDomain" is not supported. Touch web.config // to force an AppDomain restart. File.SetLastWriteTimeUtc(MapPath("~/web.config"), DateTime.UtcNow); return true; } catch { return false; } } protected virtual bool TryWriteGlobalAsax() { try { //When a new plugin is dropped in the Plugins folder and is installed into nopCommerce, //even if the plugin has registered routes for its controllers, //these routes will not be working as the MVC framework couldn't //find the new controller types and couldn't instantiate the requested controller. //That's why you get these nasty errors //i.e "Controller does not implement IController". //The issue is described here: http://www.nopcommerce.com/boards/t/10969/nop-20-plugin.aspx?p=4#51318 //The solution is to touch global.asax file File.SetLastWriteTimeUtc(MapPath("~/global.asax"), DateTime.UtcNow); return true; } catch { return false; } } #endregion #region Methods /// /// Ctor /// /// HTTP context public WebHelper(HttpContextBase httpContext) { this._httpContext = httpContext; } /// /// Get URL referrer /// /// URL referrer public virtual string GetUrlReferrer() { string referrerUrl = string.Empty; //URL referrer is null in some case (for example, in IE 8) if (IsRequestAvailable(_httpContext) && _httpContext.Request.UrlReferrer != null) referrerUrl = _httpContext.Request.UrlReferrer.PathAndQuery; return referrerUrl; } /// /// Get context IP address /// /// URL referrer public virtual string GetCurrentIpAddress() { if (!IsRequestAvailable(_httpContext)) return string.Empty; var result = ""; if (_httpContext.Request.Headers != null) { //The X-Forwarded-For (XFF) HTTP header field is a de facto standard //for identifying the originating IP address of a client //connecting to a web server through an HTTP proxy or load balancer. var forwardedHttpHeader = "X-FORWARDED-FOR"; if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["ForwardedHTTPheader"])) { //but in some cases server use other HTTP header //in these cases an administrator can specify a custom Forwarded HTTP header //e.g. CF-Connecting-IP, X-FORWARDED-PROTO, etc forwardedHttpHeader = ConfigurationManager.AppSettings["ForwardedHTTPheader"]; } //it's used for identifying the originating IP address of a client connecting to a web server //through an HTTP proxy or load balancer. string xff = _httpContext.Request.Headers.AllKeys .Where(x => forwardedHttpHeader.Equals(x, StringComparison.InvariantCultureIgnoreCase)) .Select(k => _httpContext.Request.Headers[k]) .FirstOrDefault(); //if you want to exclude private IP addresses, then see http://stackoverflow.com/questions/2577496/how-can-i-get-the-clients-ip-address-in-asp-net-mvc if (!String.IsNullOrEmpty(xff)) { string lastIp = xff.Split(new [] { ',' }).FirstOrDefault(); result = lastIp; } } if (String.IsNullOrEmpty(result) && _httpContext.Request.UserHostAddress != null) { result = _httpContext.Request.UserHostAddress; } //some validation if (result == "::1") result = "127.0.0.1"; //remove port if (!String.IsNullOrEmpty(result)) { int index = result.IndexOf(":", StringComparison.InvariantCultureIgnoreCase); if (index > 0) result = result.Substring(0, index); } return result; } /// /// Gets this page name /// /// Value indicating whether to include query strings /// Page name public virtual string GetThisPageUrl(bool includeQueryString) { bool useSsl = IsCurrentConnectionSecured(); return GetThisPageUrl(includeQueryString, useSsl); } /// /// Gets a value indicating whether current connection is secured /// /// true - secured, false - not secured public virtual bool IsCurrentConnectionSecured() { bool useSsl = false; if (IsRequestAvailable(_httpContext)) { useSsl = _httpContext.Request.IsSecureConnection; //when your hosting uses a load balancer on their server then the Request.IsSecureConnection is never got set to true, use the statement below //just uncomment it //useSSL = _httpContext.Request.ServerVariables["HTTP_CLUSTER_HTTPS"] == "on" ? true : false; } return useSsl; } /// /// Gets server variable by name /// /// Name /// Server variable public virtual string ServerVariables(string name) { string result = string.Empty; try { if (!IsRequestAvailable(_httpContext)) return result; //put this method is try-catch //as described here http://www.nopcommerce.com/boards/t/21356/multi-store-roadmap-lets-discuss-update-done.aspx?p=6#90196 if (_httpContext.Request.ServerVariables[name] != null) { result = _httpContext.Request.ServerVariables[name]; } } catch { result = string.Empty; } return result; } /// /// Returns true if the requested resource is one of the typical resources that needn't be processed by the cms engine. /// /// HTTP Request /// True if the request targets a static resource file. /// /// These are the file extensions considered to be static resources: /// .css /// .gif /// .png /// .jpg /// .jpeg /// .js /// .axd /// .ashx /// public virtual bool IsStaticResource(HttpRequest request) { if (request == null) throw new ArgumentNullException("request"); string path = request.Path; string extension = VirtualPathUtility.GetExtension(path); if (extension == null) return false; switch (extension.ToLower()) { case ".axd": case ".ashx": case ".bmp": case ".css": case ".gif": case ".htm": case ".html": case ".ico": case ".jpeg": case ".jpg": case ".js": case ".png": case ".rar": case ".zip": return true; } return false; } /// /// Maps a virtual path to a physical disk path. /// /// The path to map. E.g. "~/bin" /// The physical path. E.g. "c:\inetpub\wwwroot\bin" public virtual string MapPath(string path) { if (HostingEnvironment.IsHosted) { //hosted return HostingEnvironment.MapPath(path); } //not hosted. For example, run in unit tests string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; path = path.Replace("~/", "").TrimStart('/').Replace('/', '\\'); return Path.Combine(baseDirectory, path); } /// /// Modifies query string /// /// Url to modify /// Query string modification /// Anchor /// New url public virtual string ModifyQueryString(string url, string queryStringModification, string anchor) { if (url == null) url = string.Empty; url = url.ToLowerInvariant(); if (queryStringModification == null) queryStringModification = string.Empty; queryStringModification = queryStringModification.ToLowerInvariant(); if (anchor == null) anchor = string.Empty; anchor = anchor.ToLowerInvariant(); string str = string.Empty; string str2 = string.Empty; if (url.Contains("#")) { str2 = url.Substring(url.IndexOf("#") + 1); url = url.Substring(0, url.IndexOf("#")); } if (url.Contains("?")) { str = url.Substring(url.IndexOf("?") + 1); url = url.Substring(0, url.IndexOf("?")); } if (!string.IsNullOrEmpty(queryStringModification)) { if (!string.IsNullOrEmpty(str)) { var dictionary = new Dictionary(); foreach (string str3 in str.Split(new [] { '&' })) { if (!string.IsNullOrEmpty(str3)) { string[] strArray = str3.Split(new [] { '=' }); if (strArray.Length == 2) { if (!dictionary.ContainsKey(strArray[0])) { //do not add value if it already exists //two the same query parameters? theoretically it's not possible. //but MVC has some ugly implementation for checkboxes and we can have two values //find more info here: http://www.mindstorminteractive.com/topics/jquery-fix-asp-net-mvc-checkbox-truefalse-value/ //we do this validation just to ensure that the first one is not overridden dictionary[strArray[0]] = strArray[1]; } } else { dictionary[str3] = null; } } } foreach (string str4 in queryStringModification.Split(new [] { '&' })) { if (!string.IsNullOrEmpty(str4)) { string[] strArray2 = str4.Split(new [] { '=' }); if (strArray2.Length == 2) { dictionary[strArray2[0]] = strArray2[1]; } else { dictionary[str4] = null; } } } var builder = new StringBuilder(); foreach (string str5 in dictionary.Keys) { if (builder.Length > 0) { builder.Append("&"); } builder.Append(str5); if (dictionary[str5] != null) { builder.Append("="); builder.Append(dictionary[str5]); } } str = builder.ToString(); } else { str = queryStringModification; } } if (!string.IsNullOrEmpty(anchor)) { str2 = anchor; } return (url + (string.IsNullOrEmpty(str) ? "" : ("?" + str)) + (string.IsNullOrEmpty(str2) ? "" : ("#" + str2))).ToLowerInvariant(); } /// /// Remove query string from url /// /// Url to modify /// Query string to remove /// New url public virtual string RemoveQueryString(string url, string queryString) { if (url == null) url = string.Empty; url = url.ToLowerInvariant(); if (queryString == null) queryString = string.Empty; queryString = queryString.ToLowerInvariant(); string str = string.Empty; if (url.Contains("?")) { str = url.Substring(url.IndexOf("?") + 1); url = url.Substring(0, url.IndexOf("?")); } if (!string.IsNullOrEmpty(queryString)) { if (!string.IsNullOrEmpty(str)) { var dictionary = new Dictionary(); foreach (string str3 in str.Split(new [] { '&' })) { if (!string.IsNullOrEmpty(str3)) { string[] strArray = str3.Split(new [] { '=' }); if (strArray.Length == 2) { dictionary[strArray[0]] = strArray[1]; } else { dictionary[str3] = null; } } } dictionary.Remove(queryString); var builder = new StringBuilder(); foreach (string str5 in dictionary.Keys) { if (builder.Length > 0) { builder.Append("&"); } builder.Append(str5); if (dictionary[str5] != null) { builder.Append("="); builder.Append(dictionary[str5]); } } str = builder.ToString(); } } return (url + (string.IsNullOrEmpty(str) ? "" : ("?" + str))); } /// /// Gets query string value by name /// /// /// Parameter name /// Query string value public virtual T QueryString(string name) { string queryParam = null; if (IsRequestAvailable(_httpContext) && _httpContext.Request.QueryString[name] != null) queryParam = _httpContext.Request.QueryString[name]; if (!String.IsNullOrEmpty(queryParam)) return CommonHelper.To(queryParam); return default(T); } /// /// Restart application domain /// /// A value indicating whether we should made redirection after restart /// Redirect URL; empty string if you want to redirect to the current page URL public virtual void RestartAppDomain(bool makeRedirect = false, string redirectUrl = "") { if (CommonHelper.GetTrustLevel() > AspNetHostingPermissionLevel.Medium) { //full trust HttpRuntime.UnloadAppDomain(); TryWriteGlobalAsax(); } else { //medium trust bool success = TryWriteWebConfig(); if (!success) { throw new NopException("nopCommerce needs to be restarted due to a configuration change, but was unable to do so." + Environment.NewLine + "To prevent this issue in the future, a change to the web server configuration is required:" + Environment.NewLine + "- run the application in a full trust environment, or" + Environment.NewLine + "- give the application write access to the 'web.config' file."); } success = TryWriteGlobalAsax(); if (!success) { throw new NopException("nopCommerce needs to be restarted due to a configuration change, but was unable to do so." + Environment.NewLine + "To prevent this issue in the future, a change to the web server configuration is required:" + Environment.NewLine + "- run the application in a full trust environment, or" + Environment.NewLine + "- give the application write access to the 'Global.asax' file."); } } // If setting up extensions/modules requires an AppDomain restart, it's very unlikely the // current request can be processed correctly. So, we redirect to the same URL, so that the // new request will come to the newly started AppDomain. if (_httpContext != null && makeRedirect) { if (String.IsNullOrEmpty(redirectUrl)) redirectUrl = GetThisPageUrl(true); _httpContext.Response.Redirect(redirectUrl, true /*endResponse*/); } } /// /// Gets a value that indicates whether the client is being redirected to a new location /// public virtual bool IsRequestBeingRedirected { get { var response = _httpContext.Response; return response.IsRequestBeingRedirected; } } /// /// Gets or sets a value that indicates whether the client is being redirected to a new location using POST /// public virtual bool IsPostBeingDone { get { if (_httpContext.Items["nop.IsPOSTBeingDone"] == null) return false; return Convert.ToBoolean(_httpContext.Items["nop.IsPOSTBeingDone"]); } set { _httpContext.Items["nop.IsPOSTBeingDone"] = value; } } #endregion public string GetThisPageUrl(bool includeQueryString, bool useSsl) { throw new NotImplementedException(); } public string GetStoreHost(bool useSsl) { throw new NotImplementedException(); } public string GetStoreLocation() { throw new NotImplementedException(); } public string GetStoreLocation(bool useSsl) { throw new NotImplementedException(); } } }