2012-07-28 00:13:06 +06:00
using System ;
using System.Collections.Generic ;
using System.Configuration ;
2012-09-13 09:00:21 +07:00
using System.Linq ;
2012-07-28 00:13:06 +06:00
using System.Web ;
using System.Web.Configuration ;
2013-06-21 16:20:18 +10:00
using System.Web.Hosting ;
2012-11-14 03:32:50 +05:00
using System.Web.Routing ;
2014-02-26 02:57:05 +11:00
using System.Web.Security ;
2012-07-28 00:13:06 +06:00
using System.Xml ;
2012-10-06 18:46:12 -02:00
using System.Xml.Linq ;
2014-02-22 16:44:02 +01:00
using System.Xml.XPath ;
2012-07-28 00:13:06 +06:00
using Umbraco.Core.IO ;
2012-08-06 22:40:06 +06:00
using Umbraco.Core.Logging ;
2014-02-26 02:57:05 +11:00
using Umbraco.Core.Security ;
2012-07-28 00:13:06 +06:00
namespace Umbraco.Core.Configuration
{
2012-12-31 12:15:46 -01:00
//NOTE: Do not expose this class ever until we cleanup all configuration including removal of static classes, etc...
// we have this two tasks logged:
// http://issues.umbraco.org/issue/U4-58
// http://issues.umbraco.org/issue/U4-115
//TODO: Replace checking for if the app settings exist and returning an empty string, instead return the defaults!
2012-08-09 07:41:13 +06:00
2012-07-28 00:13:06 +06:00
/// <summary>
/// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information from web.config appsettings
/// </summary>
internal class GlobalSettings
{
2012-08-06 22:40:06 +06:00
2012-07-28 00:13:06 +06:00
#region Private static fields
2012-11-26 10:07:08 -01:00
private static Version _version ;
2013-02-27 20:42:11 +06:00
private static readonly object Locker = new object ( ) ;
//make this volatile so that we can ensure thread safety with a double check lock
private static volatile string _reservedUrlsCache ;
2012-07-28 00:13:06 +06:00
private static string _reservedPathsCache ;
private static StartsWithContainer _reservedList = new StartsWithContainer ( ) ;
2013-02-27 23:02:12 +06:00
private static string _reservedPaths ;
private static string _reservedUrls ;
//ensure the built on (non-changeable) reserved paths are there at all times
private const string StaticReservedPaths = "~/app_plugins/,~/install/," ;
2014-02-26 04:15:14 +11:00
private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd," ;
2012-07-28 00:13:06 +06:00
#endregion
2012-12-31 12:15:46 -01:00
/// <summary>
2013-03-12 12:02:04 -01:00
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
2013-02-27 22:35:27 +06:00
/// </summary>
2013-03-12 12:02:04 -01:00
private static void ResetInternal ( )
2013-02-27 22:35:27 +06:00
{
_reservedUrlsCache = null ;
2013-02-27 23:02:12 +06:00
_reservedPaths = null ;
_reservedUrls = null ;
2013-02-27 22:35:27 +06:00
}
2013-03-12 12:02:04 -01:00
/// <summary>
/// Resets settings that were set programmatically, to their initial values.
/// </summary>
/// <remarks>To be used in unit tests.</remarks>
internal static void Reset ( )
{
ResetInternal ( ) ;
}
2012-07-28 00:13:06 +06:00
/// <summary>
/// Gets the reserved urls from web.config.
/// </summary>
/// <value>The reserved urls.</value>
public static string ReservedUrls
{
get
2013-02-27 23:02:12 +06:00
{
if ( _reservedUrls = = null )
{
var urls = ConfigurationManager . AppSettings . ContainsKey ( "umbracoReservedUrls" )
? ConfigurationManager . AppSettings [ "umbracoReservedUrls" ]
: string . Empty ;
2013-02-27 20:13:15 +06:00
2013-02-27 23:02:12 +06:00
//ensure the built on (non-changeable) reserved paths are there at all times
_reservedUrls = StaticReservedUrls + urls ;
}
return _reservedUrls ;
2012-07-28 00:13:06 +06:00
}
2013-02-27 23:02:12 +06:00
internal set { _reservedUrls = value ; }
2012-07-28 00:13:06 +06:00
}
/// <summary>
/// Gets the reserved paths from web.config
/// </summary>
/// <value>The reserved paths.</value>
public static string ReservedPaths
{
get
{
2013-02-27 23:02:12 +06:00
if ( _reservedPaths = = null )
2013-02-27 20:42:11 +06:00
{
2013-02-27 23:02:12 +06:00
var reservedPaths = StaticReservedPaths ;
//always add the umbraco path to the list
if ( ConfigurationManager . AppSettings . ContainsKey ( "umbracoPath" )
& & ! ConfigurationManager . AppSettings [ "umbracoPath" ] . IsNullOrWhiteSpace ( ) )
{
reservedPaths + = ConfigurationManager . AppSettings [ "umbracoPath" ] . EnsureEndsWith ( ',' ) ;
}
2013-02-27 20:13:15 +06:00
2013-02-27 23:02:12 +06:00
var allPaths = ConfigurationManager . AppSettings . ContainsKey ( "umbracoReservedPaths" )
? ConfigurationManager . AppSettings [ "umbracoReservedPaths" ]
: string . Empty ;
2013-02-27 20:13:15 +06:00
2013-02-27 23:02:12 +06:00
_reservedPaths = reservedPaths + allPaths ;
}
return _reservedPaths ;
2012-07-28 00:13:06 +06:00
}
2013-02-27 23:02:12 +06:00
internal set { _reservedPaths = value ; }
2012-07-28 00:13:06 +06:00
}
/// <summary>
/// Gets the name of the content XML file.
/// </summary>
/// <value>The content XML.</value>
2013-06-24 13:37:25 +10:00
/// <remarks>
/// Defaults to ~/App_Data/umbraco.config
/// </remarks>
2012-09-13 09:00:21 +07:00
public static string ContentXmlFile
2012-07-28 00:13:06 +06:00
{
get
2012-12-31 12:15:46 -01:00
{
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoContentXML" )
? ConfigurationManager . AppSettings [ "umbracoContentXML" ]
2013-06-24 13:37:25 +10:00
: "~/App_Data/umbraco.config" ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the path to the storage directory (/data by default).
/// </summary>
/// <value>The storage directory.</value>
public static string StorageDirectory
{
get
{
2012-12-31 12:15:46 -01:00
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoStorageDirectory" )
? ConfigurationManager . AppSettings [ "umbracoStorageDirectory" ]
2013-06-24 13:37:25 +10:00
: "~/App_Data" ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the path to umbraco's root directory (/umbraco by default).
/// </summary>
/// <value>The path.</value>
public static string Path
{
get
{
2012-12-31 12:15:46 -01:00
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoPath" )
? IOHelper . ResolveUrl ( ConfigurationManager . AppSettings [ "umbracoPath" ] )
: string . Empty ;
}
}
/// <summary>
/// This returns the string of the MVC Area route.
/// </summary>
/// <remarks>
/// THIS IS TEMPORARY AND SHOULD BE REMOVED WHEN WE MIGRATE/UPDATE THE CONFIG SETTINGS TO BE A REAL CONFIG SECTION
/// AND SHOULD PROBABLY BE HANDLED IN A MORE ROBUST WAY.
///
/// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
/// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
/// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
2013-03-15 08:03:19 +04:00
///
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
2012-12-31 12:15:46 -01:00
/// </remarks>
internal static string UmbracoMvcArea
{
get
{
if ( Path . IsNullOrWhiteSpace ( ) )
{
throw new InvalidOperationException ( "Cannot create an MVC Area path without the umbracoPath specified" ) ;
}
2013-11-01 09:51:54 +01:00
var path = Path ;
if ( path . StartsWith ( SystemDirectories . Root ) ) // beware of TrimStart, see U4-2518
path = path . Substring ( SystemDirectories . Root . Length ) ;
return path . TrimStart ( '~' ) . TrimStart ( '/' ) . Replace ( '/' , '-' ) . Trim ( ) . ToLower ( ) ;
2012-12-31 12:15:46 -01:00
}
}
2012-09-05 09:35:24 +07:00
2012-07-28 00:13:06 +06:00
/// <summary>
/// Gets the path to umbraco's client directory (/umbraco_client by default).
/// This is a relative path to the Umbraco Path as it always must exist beside the 'umbraco'
/// folder since the CSS paths to images depend on it.
/// </summary>
/// <value>The path.</value>
public static string ClientPath
{
get
{
return Path + "/../umbraco_client" ;
}
}
/// <summary>
/// Gets the database connection string
/// </summary>
/// <value>The database connection string.</value>
2013-08-23 14:17:40 +02:00
[Obsolete("Use System.Configuration.ConfigurationManager.ConnectionStrings[\"umbracoDbDSN\"] instead ")]
2012-07-28 00:13:06 +06:00
public static string DbDsn
{
get
{
2012-12-31 12:15:46 -01:00
var settings = ConfigurationManager . ConnectionStrings [ UmbracoConnectionName ] ;
var connectionString = string . Empty ;
if ( settings ! = null )
{
connectionString = settings . ConnectionString ;
2013-08-23 14:17:40 +02:00
// The SqlCe connectionString is formatted slightly differently, so we need to update it
2012-12-31 12:15:46 -01:00
if ( settings . ProviderName . Contains ( "SqlServerCe" ) )
connectionString = string . Format ( "datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;{0}" , connectionString ) ;
}
return connectionString ;
2012-07-28 00:13:06 +06:00
}
set
{
if ( DbDsn ! = value )
{
2012-12-31 12:28:38 -01:00
if ( value . ToLower ( ) . Contains ( "SQLCE4Umbraco.SqlCEHelper" . ToLower ( ) ) )
{
2013-01-29 11:30:20 -01:00
ApplicationContext . Current . DatabaseContext . ConfigureEmbeddedDatabaseConnection ( ) ;
2012-12-31 12:28:38 -01:00
}
else
{
ApplicationContext . Current . DatabaseContext . ConfigureDatabaseConnection ( value ) ;
}
2012-07-28 00:13:06 +06:00
}
}
}
2012-10-29 09:49:31 -01:00
public const string UmbracoConnectionName = "umbracoDbDSN" ;
2012-12-27 18:52:47 -01:00
public const string UmbracoMigrationName = "Umbraco" ;
2012-10-29 09:49:31 -01:00
2012-07-28 00:13:06 +06:00
/// <summary>
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
/// </summary>
/// <value>The configuration status.</value>
public static string ConfigurationStatus
{
get
{
2012-12-31 12:15:46 -01:00
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoConfigurationStatus" )
? ConfigurationManager . AppSettings [ "umbracoConfigurationStatus" ]
: string . Empty ;
2012-07-28 00:13:06 +06:00
}
set
{
SaveSetting ( "umbracoConfigurationStatus" , value ) ;
}
}
2014-02-22 16:44:02 +01:00
/// <summary>
/// Gets or sets the Umbraco members membership providers' useLegacyEncoding state. This will return a boolean
/// </summary>
/// <value>The useLegacyEncoding status.</value>
public static bool UmbracoMembershipProviderLegacyEncoding
{
get
{
2014-02-26 02:57:05 +11:00
return IsConfiguredMembershipProviderUsingLegacyEncoding ( Constants . Conventions . Member . UmbracoMemberProviderName ) ;
2014-02-22 16:44:02 +01:00
}
set
{
SetMembershipProvidersLegacyEncoding ( Constants . Conventions . Member . UmbracoMemberProviderName , value ) ;
}
}
/// <summary>
/// Gets or sets the Umbraco users membership providers' useLegacyEncoding state. This will return a boolean
/// </summary>
/// <value>The useLegacyEncoding status.</value>
public static bool UmbracoUsersMembershipProviderLegacyEncoding
{
get
{
2014-03-18 18:52:17 +11:00
return IsConfiguredMembershipProviderUsingLegacyEncoding ( UmbracoSettings . DefaultBackofficeProvider ) ;
2014-02-22 16:44:02 +01:00
}
set
{
2014-03-18 18:52:17 +11:00
SetMembershipProvidersLegacyEncoding ( UmbracoSettings . DefaultBackofficeProvider , value ) ;
2014-02-22 16:44:02 +01:00
}
}
2012-09-13 09:00:21 +07:00
2012-07-28 00:13:06 +06:00
/// <summary>
/// Saves a setting into the configuration file.
/// </summary>
/// <param name="key">Key of the setting to be saved.</param>
/// <param name="value">Value of the setting to be saved.</param>
internal static void SaveSetting ( string key , string value )
{
2013-12-06 12:16:36 +01:00
var fileName = IOHelper . MapPath ( string . Format ( "{0}/web.config" , SystemDirectories . Root ) ) ;
2012-12-11 16:23:15 -01:00
var xml = XDocument . Load ( fileName , LoadOptions . PreserveWhitespace ) ;
2012-12-31 12:15:46 -01:00
2013-10-04 10:34:00 +10:00
var appSettings = xml . Root . DescendantsAndSelf ( "appSettings" ) . Single ( ) ;
2012-10-06 18:46:12 -02:00
// Update appSetting if it exists, or else create a new appSetting for the given key and value
2012-12-31 12:15:46 -01:00
var setting = appSettings . Descendants ( "add" ) . FirstOrDefault ( s = > s . Attribute ( "key" ) . Value = = key ) ;
2012-10-06 18:46:12 -02:00
if ( setting = = null )
appSettings . Add ( new XElement ( "add" , new XAttribute ( "key" , key ) , new XAttribute ( "value" , value ) ) ) ;
else
setting . Attribute ( "value" ) . Value = value ;
2012-12-11 16:23:15 -01:00
xml . Save ( fileName , SaveOptions . DisableFormatting ) ;
2012-07-28 00:13:06 +06:00
ConfigurationManager . RefreshSection ( "appSettings" ) ;
}
2012-12-31 12:15:46 -01:00
/// <summary>
/// Removes a setting from the configuration file.
/// </summary>
/// <param name="key">Key of the setting to be removed.</param>
internal static void RemoveSetting ( string key )
{
2013-12-06 12:16:36 +01:00
var fileName = IOHelper . MapPath ( string . Format ( "{0}/web.config" , SystemDirectories . Root ) ) ;
2012-12-31 12:15:46 -01:00
var xml = XDocument . Load ( fileName , LoadOptions . PreserveWhitespace ) ;
2013-10-04 10:34:00 +10:00
var appSettings = xml . Root . DescendantsAndSelf ( "appSettings" ) . Single ( ) ;
2012-12-31 12:15:46 -01:00
var setting = appSettings . Descendants ( "add" ) . FirstOrDefault ( s = > s . Attribute ( "key" ) . Value = = key ) ;
2013-01-07 09:39:39 -01:00
2012-12-31 12:28:38 -01:00
if ( setting ! = null )
2013-01-07 09:39:39 -01:00
{
2012-12-31 12:15:46 -01:00
setting . Remove ( ) ;
2013-01-07 09:39:39 -01:00
xml . Save ( fileName , SaveOptions . DisableFormatting ) ;
ConfigurationManager . RefreshSection ( "appSettings" ) ;
2014-02-25 02:30:05 +11:00
}
2012-12-31 12:15:46 -01:00
}
2014-02-22 16:44:02 +01:00
private static void SetMembershipProvidersLegacyEncoding ( string providerName , bool useLegacyEncoding )
{
2014-02-26 02:57:05 +11:00
//check if this can even be configured.
var membershipProvider = Membership . Providers [ providerName ] as MembershipProviderBase ;
if ( membershipProvider = = null )
{
return ;
}
if ( membershipProvider . GetType ( ) . Namespace = = "umbraco.providers.members" )
{
//its the legacy one, this cannot be changed
return ;
}
2014-02-25 02:30:05 +11:00
var webConfigFilename = IOHelper . MapPath ( string . Format ( "{0}/web.config" , SystemDirectories . Root ) ) ;
2014-02-22 16:44:02 +01:00
var webConfigXml = XDocument . Load ( webConfigFilename , LoadOptions . PreserveWhitespace ) ;
var membershipConfigs = webConfigXml . XPathSelectElements ( "configuration/system.web/membership/providers/add" ) . ToList ( ) ;
if ( membershipConfigs . Any ( ) = = false )
return ;
var provider = membershipConfigs . SingleOrDefault ( c = > c . Attribute ( "name" ) ! = null & & c . Attribute ( "name" ) . Value = = providerName ) ;
if ( provider = = null )
return ;
provider . SetAttributeValue ( "useLegacyEncoding" , useLegacyEncoding ) ;
webConfigXml . Save ( webConfigFilename , SaveOptions . DisableFormatting ) ;
}
2014-02-25 02:30:05 +11:00
2014-02-26 02:57:05 +11:00
private static bool IsConfiguredMembershipProviderUsingLegacyEncoding ( string providerName )
2014-02-22 16:44:02 +01:00
{
2014-02-26 02:57:05 +11:00
//check if this can even be configured.
var membershipProvider = Membership . Providers [ providerName ] as MembershipProviderBase ;
if ( membershipProvider = = null )
{
return false ;
}
2014-02-25 02:30:05 +11:00
2014-02-26 02:57:05 +11:00
return membershipProvider . UseLegacyEncoding ;
2014-02-25 02:30:05 +11:00
}
2012-07-28 00:13:06 +06:00
/// <summary>
/// Gets the full path to root.
/// </summary>
/// <value>The fullpath to root.</value>
public static string FullpathToRoot
{
2012-12-29 18:18:49 -01:00
get { return IOHelper . GetRootDirectorySafe ( ) ; }
2012-07-28 00:13:06 +06:00
}
/// <summary>
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
public static bool DebugMode
{
get
{
try
{
2013-06-21 16:20:18 +10:00
if ( HttpContext . Current ! = null )
{
return HttpContext . Current . IsDebuggingEnabled ;
}
//go and get it from config directly
var section = ConfigurationManager . GetSection ( "system.web/compilation" ) as CompilationSection ;
return section ! = null & & section . Debug ;
2012-07-28 00:13:06 +06:00
}
catch
{
return false ;
}
}
}
/// <summary>
/// Gets a value indicating whether the current version of umbraco is configured.
/// </summary>
/// <value><c>true</c> if configured; otherwise, <c>false</c>.</value>
public static bool Configured
{
get
{
try
{
string configStatus = ConfigurationStatus ;
2012-11-26 11:18:06 -01:00
string currentVersion = UmbracoVersion . Current . ToString ( 3 ) ;
2012-07-28 00:13:06 +06:00
if ( currentVersion ! = configStatus )
{
2012-12-31 12:15:46 -01:00
LogHelper . Debug < GlobalSettings > ( "CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'" ) ;
2012-07-28 00:13:06 +06:00
}
2012-12-31 12:15:46 -01:00
2012-07-28 00:13:06 +06:00
return ( configStatus = = currentVersion ) ;
}
catch
{
return false ;
}
}
}
/// <summary>
/// Gets the time out in minutes.
/// </summary>
/// <value>The time out in minutes.</value>
public static int TimeOutInMinutes
{
get
{
try
{
return int . Parse ( ConfigurationManager . AppSettings [ "umbracoTimeOutInMinutes" ] ) ;
}
catch
{
return 20 ;
}
}
}
/// <summary>
/// Gets a value indicating whether umbraco uses directory urls.
/// </summary>
/// <value><c>true</c> if umbraco uses directory urls; otherwise, <c>false</c>.</value>
public static bool UseDirectoryUrls
{
get
{
try
{
return bool . Parse ( ConfigurationManager . AppSettings [ "umbracoUseDirectoryUrls" ] ) ;
}
catch
{
return false ;
}
}
}
/// <summary>
/// Returns a string value to determine if umbraco should skip version-checking.
/// </summary>
/// <value>The version check period in days (0 = never).</value>
public static int VersionCheckPeriod
{
get
{
2012-12-31 12:15:46 -01:00
try
{
return int . Parse ( ConfigurationManager . AppSettings [ "umbracoVersionCheckPeriod" ] ) ;
}
catch
{
return 7 ;
}
2012-07-28 00:13:06 +06:00
}
}
2012-12-31 12:15:46 -01:00
2012-07-28 00:13:06 +06:00
/// <summary>
/// Returns a string value to determine if umbraco should disbable xslt extensions
/// </summary>
/// <value><c>"true"</c> if version xslt extensions are disabled, otherwise, <c>"false"</c></value>
2013-06-24 13:37:25 +10:00
[Obsolete("This is no longer used and will be removed from the codebase in future releases")]
2012-07-28 00:13:06 +06:00
public static string DisableXsltExtensions
{
get
{
2012-12-31 12:15:46 -01:00
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoDisableXsltExtensions" )
? ConfigurationManager . AppSettings [ "umbracoDisableXsltExtensions" ]
2013-06-24 13:37:25 +10:00
: "false" ;
}
}
internal static bool ContentCacheXmlStoredInCodeGen
{
get
{
//defaults to false
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoContentXMLUseLocalTemp" )
& & bool . Parse ( ConfigurationManager . AppSettings [ "umbracoContentXMLUseLocalTemp" ] ) ; //default to false
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Returns a string value to determine if umbraco should use Xhtml editing mode in the wysiwyg editor
/// </summary>
/// <value><c>"true"</c> if Xhtml mode is enable, otherwise, <c>"false"</c></value>
2013-06-24 13:37:25 +10:00
[Obsolete("This is no longer used and will be removed from the codebase in future releases")]
2012-07-28 00:13:06 +06:00
public static string EditXhtmlMode
{
2013-06-24 13:37:25 +10:00
get { return "true" ; }
2012-07-28 00:13:06 +06:00
}
/// <summary>
/// Gets the default UI language.
/// </summary>
/// <value>The default UI language.</value>
public static string DefaultUILanguage
{
get
{
2012-12-31 12:15:46 -01:00
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoDefaultUILanguage" )
? ConfigurationManager . AppSettings [ "umbracoDefaultUILanguage" ]
: string . Empty ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the profile URL.
/// </summary>
/// <value>The profile URL.</value>
public static string ProfileUrl
{
get
{
2013-06-24 13:37:25 +10:00
//the default will be 'profiler'
2012-12-31 12:15:46 -01:00
return ConfigurationManager . AppSettings . ContainsKey ( "umbracoProfileUrl" )
? ConfigurationManager . AppSettings [ "umbracoProfileUrl" ]
2013-06-24 13:37:25 +10:00
: "profiler" ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets a value indicating whether umbraco should hide top level nodes from generated urls.
/// </summary>
/// <value>
/// <c>true</c> if umbraco hides top level nodes from urls; otherwise, <c>false</c>.
/// </value>
public static bool HideTopLevelNodeFromPath
{
get
{
2012-12-31 12:15:46 -01:00
try
{
return bool . Parse ( ConfigurationManager . AppSettings [ "umbracoHideTopLevelNodeFromPath" ] ) ;
}
catch
{
return false ;
}
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the current version.
/// </summary>
/// <value>The current version.</value>
2012-11-26 11:18:06 -01:00
[Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)]
2012-07-28 00:13:06 +06:00
public static string CurrentVersion
{
get
{
2012-11-26 11:18:06 -01:00
return UmbracoVersion . Current . ToString ( 3 ) ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the major version number.
/// </summary>
/// <value>The major version number.</value>
2012-11-26 11:18:06 -01:00
[Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)]
2012-07-28 00:13:06 +06:00
public static int VersionMajor
{
get
{
2012-11-26 11:18:06 -01:00
return UmbracoVersion . Current . Major ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the minor version number.
/// </summary>
/// <value>The minor version number.</value>
2012-11-26 11:18:06 -01:00
[Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)]
2012-07-28 00:13:06 +06:00
public static int VersionMinor
{
get
{
2012-11-26 11:18:06 -01:00
return UmbracoVersion . Current . Minor ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the patch version number.
/// </summary>
/// <value>The patch version number.</value>
2012-11-26 11:18:06 -01:00
[Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)]
2012-07-28 00:13:06 +06:00
public static int VersionPatch
{
get
{
2012-11-26 11:18:06 -01:00
return UmbracoVersion . Current . Build ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
2012-11-26 11:18:06 -01:00
[Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)]
2012-07-28 00:13:06 +06:00
public static string VersionComment
{
get
{
2012-11-26 11:18:06 -01:00
return Umbraco . Core . Configuration . UmbracoVersion . CurrentComment ;
2012-07-28 00:13:06 +06:00
}
}
/// <summary>
/// Requests the is in umbraco application directory structure.
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public static bool RequestIsInUmbracoApplication ( HttpContext context )
{
return context . Request . Path . ToLower ( ) . IndexOf ( IOHelper . ResolveUrl ( SystemDirectories . Umbraco ) . ToLower ( ) ) > - 1 ;
}
2013-02-09 04:05:01 +06:00
public static bool RequestIsInUmbracoApplication ( HttpContextBase context )
{
return context . Request . Path . ToLower ( ) . IndexOf ( IOHelper . ResolveUrl ( SystemDirectories . Umbraco ) . ToLower ( ) ) > - 1 ;
}
2012-07-28 00:13:06 +06:00
/// <summary>
/// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice.
/// </summary>
/// <value><c>true</c> if [use SSL]; otherwise, <c>false</c>.</value>
public static bool UseSSL
{
get
{
try
{
return bool . Parse ( ConfigurationManager . AppSettings [ "umbracoUseSSL" ] ) ;
}
catch
{
return false ;
}
}
}
/// <summary>
/// Gets the umbraco license.
/// </summary>
/// <value>The license.</value>
public static string License
{
get
{
string license =
"<A href=\"http://umbraco.org/redir/license\" target=\"_blank\">the open source license MIT</A>. The umbraco UI is freeware licensed under the umbraco license." ;
2012-12-31 12:15:46 -01:00
var versionDoc = new XmlDocument ( ) ;
var versionReader = new XmlTextReader ( IOHelper . MapPath ( SystemDirectories . Umbraco + "/version.xml" ) ) ;
versionDoc . Load ( versionReader ) ;
versionReader . Close ( ) ;
// check for license
try
{
string licenseUrl =
versionDoc . SelectSingleNode ( "/version/licensing/licenseUrl" ) . FirstChild . Value ;
string licenseValidation =
versionDoc . SelectSingleNode ( "/version/licensing/licenseValidation" ) . FirstChild . Value ;
string licensedTo =
versionDoc . SelectSingleNode ( "/version/licensing/licensedTo" ) . FirstChild . Value ;
if ( licensedTo ! = "" & & licenseUrl ! = "" )
{
license = "umbraco Commercial License<br/><b>Registered to:</b><br/>" +
licensedTo . Replace ( "\n" , "<br/>" ) + "<br/><b>For use with domain:</b><br/>" +
licenseUrl ;
}
}
catch
{
}
2012-09-13 09:00:21 +07:00
return license ;
2012-07-28 00:13:06 +06:00
}
}
2012-12-31 12:15:46 -01:00
/// <summary>
/// Determines whether the current request is reserved based on the route table and
/// whether the specified URL is reserved or is inside a reserved path.
/// </summary>
/// <param name="url"></param>
/// <param name="httpContext"></param>
/// <param name="routes">The route collection to lookup the request in</param>
/// <returns></returns>
public static bool IsReservedPathOrUrl ( string url , HttpContextBase httpContext , RouteCollection routes )
{
if ( httpContext = = null ) throw new ArgumentNullException ( "httpContext" ) ;
if ( routes = = null ) throw new ArgumentNullException ( "routes" ) ;
2012-11-19 19:56:52 +05:00
2012-12-31 12:15:46 -01:00
//check if the current request matches a route, if so then it is reserved.
var route = routes . GetRouteData ( httpContext ) ;
if ( route ! = null )
return true ;
2012-11-19 19:56:52 +05:00
2012-12-31 12:15:46 -01:00
//continue with the standard ignore routine
return IsReservedPathOrUrl ( url ) ;
}
2012-11-19 19:56:52 +05:00
2012-12-31 12:15:46 -01:00
/// <summary>
2012-07-28 00:13:06 +06:00
/// Determines whether the specified URL is reserved or is inside a reserved path.
/// </summary>
/// <param name="url">The URL to check.</param>
/// <returns>
/// <c>true</c> if the specified URL is reserved; otherwise, <c>false</c>.
/// </returns>
public static bool IsReservedPathOrUrl ( string url )
2012-12-31 12:15:46 -01:00
{
2013-02-27 20:42:11 +06:00
if ( _reservedUrlsCache = = null )
2012-07-28 00:13:06 +06:00
{
2013-02-27 20:42:11 +06:00
lock ( Locker )
2012-07-28 00:13:06 +06:00
{
2013-02-27 20:42:11 +06:00
if ( _reservedUrlsCache = = null )
{
// store references to strings to determine changes
_reservedPathsCache = GlobalSettings . ReservedPaths ;
_reservedUrlsCache = GlobalSettings . ReservedUrls ;
string _root = SystemDirectories . Root . Trim ( ) . ToLower ( ) ;
// add URLs and paths to a new list
StartsWithContainer _newReservedList = new StartsWithContainer ( ) ;
foreach ( string reservedUrl in _reservedUrlsCache . Split ( new [ ] { "," } , StringSplitOptions . RemoveEmptyEntries ) )
{
2013-11-07 19:05:50 +02:00
if ( string . IsNullOrWhiteSpace ( reservedUrl ) )
continue ;
2013-11-07 19:09:50 +02:00
2013-02-27 20:42:11 +06:00
//resolves the url to support tilde chars
2013-11-07 19:09:50 +02:00
string reservedUrlTrimmed = IOHelper . ResolveUrl ( reservedUrl . Trim ( ) ) . Trim ( ) . ToLower ( ) ;
2013-02-27 20:42:11 +06:00
if ( reservedUrlTrimmed . Length > 0 )
_newReservedList . Add ( reservedUrlTrimmed ) ;
}
foreach ( string reservedPath in _reservedPathsCache . Split ( new [ ] { "," } , StringSplitOptions . RemoveEmptyEntries ) )
{
bool trimEnd = ! reservedPath . EndsWith ( "/" ) ;
2013-11-07 19:05:50 +02:00
if ( string . IsNullOrWhiteSpace ( reservedPath ) )
continue ;
2013-11-07 19:09:50 +02:00
2013-02-27 20:42:11 +06:00
//resolves the url to support tilde chars
2013-11-07 19:09:50 +02:00
string reservedPathTrimmed = IOHelper . ResolveUrl ( reservedPath . Trim ( ) ) . Trim ( ) . ToLower ( ) ;
2013-02-27 20:42:11 +06:00
if ( reservedPathTrimmed . Length > 0 )
_newReservedList . Add ( reservedPathTrimmed + ( reservedPathTrimmed . EndsWith ( "/" ) ? "" : "/" ) ) ;
}
// use the new list from now on
_reservedList = _newReservedList ;
}
2012-07-28 00:13:06 +06:00
}
}
2012-12-31 12:15:46 -01:00
//The url should be cleaned up before checking:
// * If it doesn't contain an '.' in the path then we assume it is a path based URL, if that is the case we should add an trailing '/' because all of our reservedPaths use a trailing '/'
// * We shouldn't be comparing the query at all
var pathPart = url . Split ( '?' ) [ 0 ] ;
if ( ! pathPart . Contains ( "." ) & & ! pathPart . EndsWith ( "/" ) )
{
pathPart + = "/" ;
}
2012-07-28 00:13:06 +06:00
// return true if url starts with an element of the reserved list
2012-12-31 12:15:46 -01:00
return _reservedList . StartsWith ( pathPart . ToLowerInvariant ( ) ) ;
}
/// <summary>
/// Structure that checks in logarithmic time
/// if a given string starts with one of the added keys.
/// </summary>
private class StartsWithContainer
{
/// <summary>Internal sorted list of keys.</summary>
public SortedList < string , string > _list
= new SortedList < string , string > ( StartsWithComparator . Instance ) ;
/// <summary>
/// Adds the specified new key.
/// </summary>
/// <param name="newKey">The new key.</param>
public void Add ( string newKey )
{
// if the list already contains an element that begins with newKey, return
if ( String . IsNullOrEmpty ( newKey ) | | StartsWith ( newKey ) )
return ;
// create a new collection, so the old one can still be accessed
SortedList < string , string > newList
= new SortedList < string , string > ( _list . Count + 1 , StartsWithComparator . Instance ) ;
// add only keys that don't already start with newKey, others are unnecessary
foreach ( string key in _list . Keys )
if ( ! key . StartsWith ( newKey ) )
newList . Add ( key , null ) ;
// add the new key
newList . Add ( newKey , null ) ;
// update the list (thread safe, _list was never in incomplete state)
_list = newList ;
}
/// <summary>
/// Checks if the given string starts with any of the added keys.
/// </summary>
/// <param name="target">The target.</param>
/// <returns>true if a key is found that matches the start of target</returns>
/// <remarks>
/// Runs in O(s*log(n)), with n the number of keys and s the length of target.
/// </remarks>
public bool StartsWith ( string target )
{
return _list . ContainsKey ( target ) ;
}
/// <summary>Comparator that tests if a string starts with another.</summary>
/// <remarks>Not a real comparator, since it is not reflexive. (x==y does not imply y==x)</remarks>
private sealed class StartsWithComparator : IComparer < string >
{
/// <summary>Default string comparer.</summary>
private readonly static Comparer < string > _stringComparer = Comparer < string > . Default ;
/// <summary>Gets an instance of the StartsWithComparator.</summary>
public static readonly StartsWithComparator Instance = new StartsWithComparator ( ) ;
/// <summary>
/// Tests if whole begins with all characters of part.
/// </summary>
/// <param name="part">The part.</param>
/// <param name="whole">The whole.</param>
/// <returns>
/// Returns 0 if whole starts with part, otherwise performs standard string comparison.
/// </returns>
public int Compare ( string part , string whole )
{
// let the default string comparer deal with null or when part is not smaller then whole
if ( part = = null | | whole = = null | | part . Length > = whole . Length )
return _stringComparer . Compare ( part , whole ) ;
////ensure both have a / on the end
//part = part.EndsWith("/") ? part : part + "/";
//whole = whole.EndsWith("/") ? whole : whole + "/";
//if (part.Length >= whole.Length)
// return _stringComparer.Compare(part, whole);
// loop through all characters that part and whole have in common
int pos = 0 ;
bool match ;
do
{
match = ( part [ pos ] = = whole [ pos ] ) ;
} while ( match & & + + pos < part . Length ) ;
// return result of last comparison
return match ? 0 : ( part [ pos ] < whole [ pos ] ? - 1 : 1 ) ;
}
}
}
2012-07-28 00:13:06 +06:00
}
2012-12-31 12:15:46 -01:00
2012-07-28 00:13:06 +06:00
}