1 //------------------------------------------------------------------------------
2 // <copyright file="WebConfigurationHost.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
9 namespace System.Web.Configuration {
10 using System.Collections;
11 using System.Configuration.Internal;
12 using System.Configuration;
13 using System.Globalization;
15 using System.Reflection;
16 using System.Security;
17 using System.Security.Policy;
18 using System.Security.Permissions;
20 using System.Web.Compilation;
21 using System.Web.Configuration.Internal;
22 using System.Web.Hosting;
23 using System.Web.Util;
26 using System.Runtime.InteropServices;
27 using Microsoft.Build.Utilities;
30 // Configuration host for web applications.
32 internal sealed class WebConfigurationHost : DelegatingConfigHost, IInternalConfigWebHost {
33 const string InternalHostTypeName = "System.Configuration.Internal.InternalConfigHost, " + AssemblyRef.SystemConfiguration;
34 const string InternalConfigConfigurationFactoryTypeName = "System.Configuration.Internal.InternalConfigConfigurationFactory, " + AssemblyRef.SystemConfiguration;
36 internal const string MachineConfigName = "machine";
37 internal const string MachineConfigPath = "machine";
38 internal const string RootWebConfigName = "webroot";
39 internal const string RootWebConfigPath = "machine/webroot";
41 internal const char PathSeparator = '/';
42 internal const string DefaultSiteID = "1";
43 private static readonly string RootWebConfigPathAndPathSeparator = RootWebConfigPath + PathSeparator;
44 private static readonly string RootWebConfigPathAndDefaultSiteID = RootWebConfigPathAndPathSeparator + DefaultSiteID;
46 internal static readonly char[] s_slashSplit;
47 private static IInternalConfigConfigurationFactory s_configurationFactory;
48 private static string s_defaultSiteName;
50 private Hashtable _fileChangeCallbacks; // filename -> arraylist of filechangecallbacks
51 private IConfigMapPath _configMapPath; // mappath implementation
52 private IConfigMapPath2 _configMapPath2; // mappath implementation that supports VirtualPath
53 private VirtualPath _appPath; // the application's path
54 private string _appSiteName; // the application's site name
55 private string _appSiteID; // the application's site ID
56 private string _appConfigPath; // the application's configPath
57 private string _machineConfigFile;
58 private string _rootWebConfigFile;
65 static WebConfigurationHost() {
66 s_slashSplit = new char[PathSeparator];
69 static internal string DefaultSiteName {
71 if (s_defaultSiteName == null) {
72 s_defaultSiteName = SR.GetString(SR.DefaultSiteName);
75 return s_defaultSiteName;
79 internal WebConfigurationHost() {
80 Type type = Type.GetType(InternalHostTypeName, true);
81 Host = (IInternalConfigHost) Activator.CreateInstance(type, true);
84 // Not used in runtime because in runtime we have all the siteid, appPath, etc. already.
85 static internal void GetConfigPaths(IConfigMapPath configMapPath, WebLevel webLevel, VirtualPath virtualPath, string site, string locationSubPath,
86 out VirtualPath appPath, out string appSiteName, out string appSiteID, out string configPath, out string locationConfigPath) {
92 if (webLevel == WebLevel.Machine || virtualPath == null) {
93 // Site is meaningless at machine and root web.config level
94 // However, we allow a site parameter if the caller is opening
95 // a location tag. See VSWhidbey 548361.
96 if (!String.IsNullOrEmpty(site) && String.IsNullOrEmpty(locationSubPath)) {
97 throw ExceptionUtil.ParameterInvalid("site");
100 if (webLevel == WebLevel.Machine) {
101 configPath = MachineConfigPath;
104 configPath = RootWebConfigPath;
108 // Get the site name and ID
109 if (!String.IsNullOrEmpty(site)) {
110 configMapPath.ResolveSiteArgument(site, out appSiteName, out appSiteID);
112 if (String.IsNullOrEmpty(appSiteID)) {
113 throw new InvalidOperationException(SR.GetString(SR.Config_failed_to_resolve_site_id, site));
117 // If site not supplied, try hosting environment first
118 if (HostingEnvironment.IsHosted) {
119 appSiteName = HostingEnvironment.SiteNameNoDemand;
120 appSiteID = HostingEnvironment.SiteID;
123 // Rely on defaults if not provided in hosting environment
124 if (String.IsNullOrEmpty(appSiteID)) {
125 configMapPath.GetDefaultSiteNameAndID(out appSiteName, out appSiteID);
128 Debug.Assert(!String.IsNullOrEmpty(appSiteID), "No appSiteID found when site argument is null");
131 configPath = GetConfigPathFromSiteIDAndVPath(appSiteID, virtualPath);
134 // get locationConfigPath
135 locationConfigPath = null;
136 string locationSite = null;
137 VirtualPath locationVPath = null;
138 if (locationSubPath != null) {
139 locationConfigPath = GetConfigPathFromLocationSubPathBasic(configPath, locationSubPath);
140 GetSiteIDAndVPathFromConfigPath(locationConfigPath, out locationSite, out locationVPath);
142 // If we're at machine or root web.config level and a location path is given,
143 // handle the site part of the location path.
144 if (String.IsNullOrEmpty(appSiteID) && !String.IsNullOrEmpty(locationSite)) {
145 configMapPath.ResolveSiteArgument(locationSite, out appSiteName, out appSiteID);
146 if (!String.IsNullOrEmpty(appSiteID)) {
147 // Recompose the location config path based on new appSiteID
148 locationConfigPath = GetConfigPathFromSiteIDAndVPath(appSiteID, locationVPath);
151 // If there is no path, then allow the location to be edited,
152 // as we don't need to map elements of the path.
153 if (locationVPath == null || locationVPath.VirtualPathString == "/") {
154 appSiteName = locationSite;
155 appSiteID = locationSite;
157 // Otherwise, the site argument is ambiguous.
169 string appPathString = null;
170 if (locationVPath != null) {
171 appPathString = configMapPath.GetAppPathForPath(appSiteID, locationVPath.VirtualPathString);
173 else if (virtualPath != null) {
174 appPathString = configMapPath.GetAppPathForPath(appSiteID, virtualPath.VirtualPathString);
177 if (appPathString != null) {
178 appPath = VirtualPath.Create(appPathString);
182 // Choose the implementation of IConfigMapPath to use
183 // in cases where it is not provided to us.
184 void ChooseAndInitConfigMapPath(bool useConfigMapPath, IConfigMapPath configMapPath, ConfigurationFileMap fileMap) {
185 if (useConfigMapPath) {
186 _configMapPath = configMapPath;
188 else if (fileMap != null) {
189 _configMapPath = new UserMapPath(fileMap);
191 else if (HostingEnvironment.IsHosted) {
192 _configMapPath = HostingPreferredMapPath.GetInstance();
195 _configMapPath = IISMapPath.GetInstance();
198 // see if it supports IConfigMapPath2
199 _configMapPath2 = _configMapPath as IConfigMapPath2;
202 public override void Init(IInternalConfigRoot configRoot, params object[] hostInitParams) {
203 bool useConfigMapPath = (bool) hostInitParams[0];
204 IConfigMapPath configMapPath = (IConfigMapPath) hostInitParams[1];
205 ConfigurationFileMap fileMap = (ConfigurationFileMap) hostInitParams[2];
206 string appPath = (string) hostInitParams[3];
207 string appSiteName = (string) hostInitParams[4];
208 string appSiteID = (string) hostInitParams[5];
210 if (hostInitParams.Length > 6) {
211 // If VS sent a 7th param, it is the .Net Framwework Target version moniker
212 string fxMoniker = hostInitParams[6] as string;
213 _machineConfigFile = GetMachineConfigPathFromTargetFrameworkMoniker(fxMoniker);
214 if (!string.IsNullOrEmpty(_machineConfigFile)) {
215 _rootWebConfigFile = Path.Combine(Path.GetDirectoryName(_machineConfigFile), "web.config");
219 Debug.Assert(configMapPath == null || useConfigMapPath, "non-null configMapPath without useConfigMapPath == true");
221 Host.Init(configRoot, hostInitParams);
223 ChooseAndInitConfigMapPath(useConfigMapPath, configMapPath, fileMap);
225 appPath = UrlPath.RemoveSlashFromPathIfNeeded(appPath);
226 _appPath = VirtualPath.CreateAbsoluteAllowNull(appPath);
227 _appSiteName = appSiteName;
228 _appSiteID = appSiteID;
230 if (!String.IsNullOrEmpty(_appSiteID) && _appPath != null) {
231 _appConfigPath = GetConfigPathFromSiteIDAndVPath(_appSiteID, _appPath);
239 public override void InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath,
240 IInternalConfigRoot configRoot, params object[] hostInitConfigurationParams) {
243 WebLevel webLevel = (WebLevel) hostInitConfigurationParams[0];
244 ConfigurationFileMap fileMap = (ConfigurationFileMap) hostInitConfigurationParams[1];
245 VirtualPath path = VirtualPath.CreateAbsoluteAllowNull((string)hostInitConfigurationParams[2]);
246 string site = (string) hostInitConfigurationParams[3];
248 if (locationSubPath == null) {
249 locationSubPath = (string) hostInitConfigurationParams[4];
252 Host.Init(configRoot, hostInitConfigurationParams);
254 // Choose the implementation of IConfigMapPath.
255 ChooseAndInitConfigMapPath(false, null, fileMap);
257 // Get the configuration paths and application information
258 GetConfigPaths(_configMapPath, webLevel, path, site, locationSubPath, out _appPath, out _appSiteName, out _appSiteID, out configPath, out locationConfigPath);
259 _appConfigPath = GetConfigPathFromSiteIDAndVPath(_appSiteID, _appPath);
261 // Verify that the site and path arguments represent a valid name
262 // For example, in Cassini app, which is running on \myApp, a page can
263 // ask for the config for "\", which can't map to anything. We want
264 // to catch this kind of error. Another example is if we're given
265 // an invalid site id.
266 if (IsVirtualPathConfigPath(configPath)) {
268 VirtualPath finalPath;
269 GetSiteIDAndVPathFromConfigPath(configPath, out finalSiteID, out finalPath);
273 // attempt to use IConfigMapPath2 if provider supports it
274 if (null != _configMapPath2) {
275 physicalPath = _configMapPath2.MapPath(finalSiteID, finalPath);
278 physicalPath = _configMapPath.MapPath(finalSiteID, finalPath.VirtualPathString);
281 if (String.IsNullOrEmpty(physicalPath)) {
282 throw new ArgumentOutOfRangeException("site");
293 // Utilities to parse config path
295 // In both WHIDBEY and ORCAS, Path has the format:
296 // MACHINE/WEBROOT/[Site ID]/[Path Component]/[Path Component]/...
299 static internal bool IsMachineConfigPath(string configPath) {
300 return configPath.Length == MachineConfigPath.Length;
303 static internal bool IsRootWebConfigPath(string configPath) {
304 return configPath.Length == RootWebConfigPath.Length;
307 // Does the configPath represent a virtual path?
308 static internal bool IsVirtualPathConfigPath(string configPath) {
309 return configPath.Length > RootWebConfigPath.Length;
312 // A site argument that begins or ends in slashes will prevent
313 // us from using it in a configPath
314 static internal bool IsValidSiteArgument(string site) {
315 if (!String.IsNullOrEmpty(site)) {
316 char first = site[0];
317 char last = site[site.Length - 1];
319 if (first == '/' || first == '\\' || last == '/' || last == '\\') {
327 // Return the virtual path from the configPath.
328 static internal string VPathFromConfigPath(string configPath) {
329 if (!IsVirtualPathConfigPath(configPath))
332 // Return the path part after [SiteName]
333 int indexStart = RootWebConfigPath.Length + 1;
334 int indexVPath = configPath.IndexOf(PathSeparator, indexStart);
335 if (indexVPath == -1) {
339 return configPath.Substring(indexVPath);
342 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
343 void IInternalConfigWebHost.GetSiteIDAndVPathFromConfigPath(string configPath, out string siteID, out string vpath) {
344 VirtualPath virtualPath;
345 WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out virtualPath);
346 vpath = VirtualPath.GetVirtualPathString(virtualPath);
349 static internal void GetSiteIDAndVPathFromConfigPath(string configPath, out string siteID, out VirtualPath vpath) {
350 if (!IsVirtualPathConfigPath(configPath)) {
356 int indexStart = RootWebConfigPath.Length + 1;
357 int indexVPath = configPath.IndexOf(PathSeparator, indexStart);
359 if (indexVPath == -1) {
360 length = configPath.Length - indexStart;
363 length = indexVPath - indexStart;
366 siteID = configPath.Substring(indexStart, length);
367 if (indexVPath == -1) {
368 vpath = VirtualPath.RootVirtualPath;
371 vpath = VirtualPath.CreateAbsolute(configPath.Substring(indexVPath));
375 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
376 string IInternalConfigWebHost.GetConfigPathFromSiteIDAndVPath(string siteID, string vpath) {
377 return WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(
378 siteID, VirtualPath.CreateAbsoluteAllowNull(vpath));
381 static internal string GetConfigPathFromSiteIDAndVPath(string siteID, VirtualPath vpath) {
383 // Do not inadverte expand app-relative paths using appdomain
384 Debug.Assert(vpath == null || vpath.VirtualPathStringIfAvailable != null || vpath.AppRelativeVirtualPathStringIfAvailable == null,
385 "vpath == null || vpath.VirtualPathStringIfAvailable != null || vpath.AppRelativeVirtualPathStringIfAvailable == null");
388 if (vpath == null || string.IsNullOrEmpty(siteID)) {
389 return RootWebConfigPath;
392 string virtualPath = vpath.VirtualPathStringNoTrailingSlash.ToLower(CultureInfo.InvariantCulture);
393 string configPath = (siteID == DefaultSiteID) ? RootWebConfigPathAndDefaultSiteID : RootWebConfigPathAndPathSeparator + siteID;
394 if (virtualPath.Length > 1) {
395 configPath += virtualPath;
400 static internal string CombineConfigPath(string parentConfigPath, string childConfigPath) {
401 if (String.IsNullOrEmpty(parentConfigPath)) {
402 return childConfigPath;
405 if (String.IsNullOrEmpty(childConfigPath)) {
406 return parentConfigPath;
409 return parentConfigPath + PathSeparator + childConfigPath;
412 public override bool IsConfigRecordRequired(string configPath) {
413 // machine.config and root web.config are required records
414 if (!IsVirtualPathConfigPath(configPath))
417 // find the physical translation
420 GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out path);
424 // attempt to use fast path VirtualPath interface
425 if (null != _configMapPath2) {
426 physicalPath = _configMapPath2.MapPath(siteID, path);
429 physicalPath = _configMapPath.MapPath(siteID, path.VirtualPathString);
432 // If the mapping doesn't exist, it may contain children.
433 // For example, a Cassini server running application
434 // "/myApp" will not have a mapping for "/".
435 if (physicalPath == null)
438 // vpaths that correspond to directories are required
439 return FileUtil.DirectoryExists(physicalPath, true);
443 public override string GetStreamName(string configPath) {
444 if (IsMachineConfigPath(configPath)) {
445 return !string.IsNullOrEmpty(_machineConfigFile) ? _machineConfigFile : _configMapPath.GetMachineConfigFilename();
447 if (IsRootWebConfigPath(configPath)) {
448 return !string.IsNullOrEmpty(_rootWebConfigFile) ? _rootWebConfigFile : _configMapPath.GetRootWebConfigFilename();
453 GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out path);
455 string directory, baseName;
457 // attempt to use fast path interface that takes a VirtualPath
458 // to avoid conversion
459 if (null != _configMapPath2) {
460 _configMapPath2.GetPathConfigFilename(siteID, path, out directory, out baseName);
463 _configMapPath.GetPathConfigFilename(siteID, path.VirtualPathString, out directory, out baseName);
465 if (directory == null)
468 bool exists, isDirectory;
469 FileUtil.PhysicalPathStatus(directory, true, false, out exists, out isDirectory);
470 if (exists && isDirectory) {
471 // DevDiv Bugs 152256: Illegal characters {",|} in path prevent configuration system from working.
472 // We need to catch this exception and return null as System.IO.Path.Combine fails to combine paths
473 // containing these characters.
474 // We return null when we have an ArgumentException because we have characters in the parameters
475 // that cannot be part of a filename in Windows. So it is impossible to get a stream name for paths
476 // with these characters. We fallback to the default GetStreamName failure behavior which is to
479 // Dev10 Bug 835901: '?' (%3F), '*' (%2A), and ':' (%3A) are valid in a URL. We need to return null
480 // if the path contains one of these characters. Instead of explicitly checking for these characters,
481 // we will rely on Path.Combine and Path.GetFullPath to throw when the path is invalid.
482 return CombineAndValidatePath(directory, baseName);
489 [FileIOPermissionAttribute(SecurityAction.Assert, AllFiles=FileIOPermissionAccess.PathDiscovery)]
490 private string CombineAndValidatePath(string directory, string baseName) {
492 string path = Path.Combine(directory, baseName);
493 // validate path by calling GetFullPath, but return the result of Path.Combine so as
494 // not to change what was being returned previously (Dev10 835901).
495 Path.GetFullPath(path);
498 catch (PathTooLongException) {
501 catch (NotSupportedException) {
504 catch (ArgumentException) {
509 // change notification support - runtime only
510 public override bool SupportsChangeNotifications {
514 private Hashtable FileChangeCallbacks {
516 if (_fileChangeCallbacks == null) {
517 _fileChangeCallbacks = new Hashtable(StringComparer.OrdinalIgnoreCase);
520 return _fileChangeCallbacks;
524 public override object StartMonitoringStreamForChanges(string streamName, StreamChangeCallback callback) {
525 WebConfigurationHostFileChange wrapper;
527 // Note: in theory it's possible for multiple config records to monitor the same stream.
528 // That's why we use the arraylist to store the callbacks.
530 wrapper = new WebConfigurationHostFileChange(callback);
531 ArrayList list = (ArrayList) FileChangeCallbacks[streamName];
533 list = new ArrayList(1);
534 FileChangeCallbacks.Add(streamName, list);
540 HttpRuntime.FileChangesMonitor.StartMonitoringFile(
541 streamName, new FileChangeEventHandler(wrapper.OnFileChanged));
546 public override void StopMonitoringStreamForChanges(string streamName, StreamChangeCallback callback) {
547 WebConfigurationHostFileChange wrapper = null;
549 ArrayList list = (ArrayList) FileChangeCallbacks[streamName];
550 for (int i = 0; i < list.Count; i++) {
551 WebConfigurationHostFileChange item = (WebConfigurationHostFileChange) list[i];
552 if (object.ReferenceEquals(item.Callback, callback)) {
555 if (list.Count == 0) {
556 FileChangeCallbacks.Remove(streamName);
563 HttpRuntime.FileChangesMonitor.StopMonitoringFile(streamName, wrapper);
566 public override bool IsDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition) {
567 switch (allowDefinition) {
568 case ConfigurationAllowDefinition.MachineOnly:
569 return configPath.Length <= MachineConfigPath.Length;
571 case ConfigurationAllowDefinition.MachineToWebRoot:
572 return configPath.Length <= RootWebConfigPath.Length;
574 case ConfigurationAllowDefinition.MachineToApplication:
575 // In some scenarios the host does not have an application path.
576 // Allow all definitions in this case.
577 return String.IsNullOrEmpty(_appConfigPath) ||
578 (configPath.Length <= _appConfigPath.Length) ||
579 IsApplication(configPath);
581 // MachineToLocalUser does not current have any definition restrictions
582 case ConfigurationAllowDefinition.Everywhere:
586 // If we have extended ConfigurationAllowDefinition
587 // make sure to update this switch accordingly
588 throw ExceptionUtil.UnexpectedError("WebConfigurationHost::IsDefinitionAllowed");
592 public override void VerifyDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition, IConfigErrorInfo errorInfo) {
593 if (!IsDefinitionAllowed(configPath, allowDefinition, allowExeDefinition)) {
594 switch (allowDefinition) {
595 case ConfigurationAllowDefinition.MachineOnly:
596 throw new ConfigurationErrorsException(SR.GetString(SR.Config_allow_definition_error_machine), errorInfo.Filename, errorInfo.LineNumber);
598 case ConfigurationAllowDefinition.MachineToWebRoot:
599 throw new ConfigurationErrorsException(SR.GetString(SR.Config_allow_definition_error_webroot), errorInfo.Filename, errorInfo.LineNumber);
601 case ConfigurationAllowDefinition.MachineToApplication:
602 throw new ConfigurationErrorsException(SR.GetString(SR.Config_allow_definition_error_application), errorInfo.Filename, errorInfo.LineNumber);
605 // If we have extended ConfigurationAllowDefinition
606 // make sure to update this switch accordingly
607 throw ExceptionUtil.UnexpectedError("WebConfigurationHost::VerifyDefinitionAllowed");
612 private WebApplicationLevel GetPathLevel(string configPath) {
613 if (!IsVirtualPathConfigPath(configPath))
614 return WebApplicationLevel.AboveApplication;
617 Debug.Assert(_inited, "_inited");
620 // Disable handling of path level when we don't have an application path.
621 if (_appPath == null)
622 return WebApplicationLevel.AboveApplication;
626 GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out path);
627 if (!StringUtil.EqualsIgnoreCase(_appSiteID, siteID))
628 return WebApplicationLevel.AboveApplication;
630 if (_appPath == path)
631 return WebApplicationLevel.AtApplication;
633 if (UrlPath.IsEqualOrSubpath(_appPath.VirtualPathString, path.VirtualPathString))
634 return WebApplicationLevel.BelowApplication;
636 return WebApplicationLevel.AboveApplication;
640 public override bool SupportsPath {
646 public override bool SupportsLocation {
652 public override bool IsAboveApplication(string configPath) {
653 return GetPathLevel(configPath) == WebApplicationLevel.AboveApplication;
656 static internal string GetConfigPathFromLocationSubPathBasic(string configPath, string locationSubPath) {
657 string locationConfigPath;
659 if (IsVirtualPathConfigPath(configPath)) {
660 locationConfigPath = CombineConfigPath(configPath, locationSubPath);
663 // Location subpaths only apply to virtual paths, not config file roots.
664 locationConfigPath = CombineConfigPath(RootWebConfigPath, locationSubPath);
667 return locationConfigPath;
670 public override string GetConfigPathFromLocationSubPath(string configPath, string locationSubPath) {
672 Debug.Assert(_inited, "_inited");
675 string locationConfigPath;
677 if (IsVirtualPathConfigPath(configPath)) {
678 locationConfigPath = CombineConfigPath(configPath, locationSubPath);
681 string siteID = null;
683 // First part of path is the site.
684 // If it matches this app's site, use the proper site id,
685 // otherwise just use the site as it is given, which will
686 // result in it being ignored as desired.
688 VirtualPath virtualPath;
689 int firstSlash = locationSubPath.IndexOf(PathSeparator);
690 if (firstSlash < 0) {
691 site = locationSubPath;
692 virtualPath = VirtualPath.RootVirtualPath;
695 site = locationSubPath.Substring(0, firstSlash);
696 virtualPath = VirtualPath.CreateAbsolute(locationSubPath.Substring(firstSlash));
699 if (StringUtil.EqualsIgnoreCase(site, _appSiteID) || StringUtil.EqualsIgnoreCase(site, _appSiteName)) {
706 locationConfigPath = GetConfigPathFromSiteIDAndVPath(siteID, virtualPath);
709 return locationConfigPath;
712 public override bool IsLocationApplicable(string configPath) {
713 return IsVirtualPathConfigPath(configPath);
716 internal static void StaticGetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady) {
717 isHostReady = HttpRuntime.IsTrustLevelInitialized;
718 permissionSet = null;
719 if (isHostReady && IsVirtualPathConfigPath(configRecord.ConfigPath)) {
720 permissionSet = HttpRuntime.NamedPermissionSet;
724 // we trust root config files - admins settings do not have security restrictions.
725 public override bool IsTrustedConfigPath(string configPath) {
726 return !IsVirtualPathConfigPath(configPath);
729 public override bool IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord) {
730 if (HostingEnvironment.IsHosted) {
731 return HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted);
734 return Host.IsFullTrustSectionWithoutAptcaAllowed(configRecord);
738 public override void GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady) {
739 StaticGetRestrictedPermissions(configRecord, out permissionSet, out isHostReady);
742 public override IDisposable Impersonate() {
743 return new ApplicationImpersonationContext();
747 public override bool PrefetchAll(string configPath, string streamName) {
748 return !IsMachineConfigPath(configPath);
751 const string SysWebName = "system.web";
752 public override bool PrefetchSection(string sectionGroupName, string sectionName) {
753 if ( StringUtil.StringStartsWith(sectionGroupName, SysWebName)
754 && (sectionGroupName.Length == SysWebName.Length || sectionGroupName[SysWebName.Length] == '/')) {
759 if (String.IsNullOrEmpty(sectionGroupName) && sectionName == "system.codedom")
766 public override object CreateDeprecatedConfigContext(string configPath) {
767 return new HttpConfigurationContext(VPathFromConfigPath(configPath));
770 // CreateConfigurationContext
772 // Create the ConfigurationContext for ConfigurationElement's
775 // configPath - Config Path we are quering for
776 // locationSubPath - Location SubPath
778 public override object CreateConfigurationContext(string configPath, string locationSubPath)
781 WebApplicationLevel pathLevel;
783 path = VPathFromConfigPath(configPath);
784 pathLevel = GetPathLevel(configPath);
786 return new WebContext( pathLevel, // PathLevel
787 _appSiteName, // Site
788 VirtualPath.GetVirtualPathString(_appPath), // AppPath
790 locationSubPath, // LocationSubPath
791 _appConfigPath); // e.g., "machine/webroot/2/approot"
795 public override Type GetConfigType(string typeName, bool throwOnError) {
796 // Go through BuildManager to allow simple references to types in the
797 // code directory (VSWhidbey 284498)
798 return BuildManager.GetType(typeName, throwOnError);
801 public override string GetConfigTypeName(Type t) {
802 return BuildManager.GetNormalizedTypeName(t);
807 // Given a config Path, is it the Path for an application?
809 private bool IsApplication(string configPath) {
814 // Break up into siteID and vpath
815 GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out vpath);
817 // Retrieve appPath for this
818 if (null != _configMapPath2) {
819 appPath = _configMapPath2.GetAppPathForPath(siteID, vpath);
822 appPath = VirtualPath.CreateAllowNull(_configMapPath.GetAppPathForPath(siteID, vpath.VirtualPathString));
825 return (appPath == vpath);
828 // Get the factory used to create and initialize Configuration objects.
829 static internal IInternalConfigConfigurationFactory ConfigurationFactory {
830 [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.MemberAccess)]
832 if (s_configurationFactory == null) {
833 Type type = Type.GetType(InternalConfigConfigurationFactoryTypeName, true);
834 s_configurationFactory = (IInternalConfigConfigurationFactory) Activator.CreateInstance(type, true);
837 return s_configurationFactory;
841 // Create an instance of a Configuration object.
842 // Used by design-time API to open a Configuration object.
843 static internal Configuration OpenConfiguration(
844 WebLevel webLevel, ConfigurationFileMap fileMap, VirtualPath path, string site, string locationSubPath,
845 string server, string userName, string password, IntPtr tokenHandle) {
847 Configuration configuration;
849 if (!IsValidSiteArgument(site)) {
850 throw ExceptionUtil.ParameterInvalid("site");
853 locationSubPath = ConfigurationFactory.NormalizeLocationSubPath(locationSubPath, null);
855 bool isRemote = !String.IsNullOrEmpty(server)
857 && !StringUtil.EqualsIgnoreCase(server, "127.0.0.1")
858 && !StringUtil.EqualsIgnoreCase(server, "::1")
859 && !StringUtil.EqualsIgnoreCase(server, "localhost")
860 && !StringUtil.EqualsIgnoreCase(server, Environment.MachineName);
864 configuration = ConfigurationFactory.Create(typeof(RemoteWebConfigurationHost),
865 webLevel, null, VirtualPath.GetVirtualPathString(path), site, locationSubPath, server, userName, password, tokenHandle);
868 if (String.IsNullOrEmpty(server)) {
869 if (!String.IsNullOrEmpty(userName))
870 throw ExceptionUtil.ParameterInvalid("userName");
872 if (!String.IsNullOrEmpty(password))
873 throw ExceptionUtil.ParameterInvalid("password");
875 if (tokenHandle != (IntPtr) 0)
876 throw ExceptionUtil.ParameterInvalid("tokenHandle");
879 // Create a copy of the fileMap, so that it cannot be altered by
880 // its creator once we start using it.
881 if (fileMap != null) {
882 fileMap = (ConfigurationFileMap) fileMap.Clone();
885 WebConfigurationFileMap webFileMap = fileMap as WebConfigurationFileMap;
886 if (webFileMap != null && !String.IsNullOrEmpty(site)) {
887 webFileMap.Site = site;
890 configuration = ConfigurationFactory.Create(typeof(WebConfigurationHost),
891 webLevel, fileMap, VirtualPath.GetVirtualPathString(path), site, locationSubPath );
894 return configuration;
898 private static string GetMachineConfigPathFromTargetFrameworkMoniker(string moniker) {
899 TargetDotNetFrameworkVersion ver = GetTargetFrameworkVersionEnumFromMoniker(moniker);
900 if (ver == TargetDotNetFrameworkVersion.VersionLatest)
903 string machineConfig = ToolLocationHelper.GetPathToDotNetFrameworkFile(@"config\machine.config", ver);
904 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, machineConfig).Demand();
905 return machineConfig;
908 private static TargetDotNetFrameworkVersion GetTargetFrameworkVersionEnumFromMoniker(string moniker)
912 if (moniker.Contains("3.5") || moniker.Contains("3.0") || moniker.Contains("2.0") ) {
913 return TargetDotNetFrameworkVersion.Version20;
915 return TargetDotNetFrameworkVersion.VersionLatest;