Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Web / Configuration / WebConfigurationHost.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="WebConfigurationHost.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 #define YES
8
9 namespace System.Web.Configuration {
10     using System.Collections;
11     using System.Configuration.Internal;
12     using System.Configuration;
13     using System.Globalization;
14     using System.IO;
15     using System.Reflection;
16     using System.Security;
17     using System.Security.Policy;
18     using System.Security.Permissions;
19     using System.Web;
20     using System.Web.Compilation;
21     using System.Web.Configuration.Internal;
22     using System.Web.Hosting;
23     using System.Web.Util;
24     using System.Xml;
25     using System.Text;
26     using System.Runtime.InteropServices;
27     using Microsoft.Build.Utilities;
28
29     //
30     // Configuration host for web applications.
31     //
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;
35
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";
40
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;
45
46         internal static readonly char[]                     s_slashSplit;
47         private static IInternalConfigConfigurationFactory  s_configurationFactory;
48         private static string                               s_defaultSiteName;
49
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;
59
60
61 #if DBG
62         private bool            _inited;
63 #endif
64
65          static WebConfigurationHost() {
66             s_slashSplit = new char[PathSeparator];
67         }
68
69         static internal string DefaultSiteName {
70             get {
71                 if (s_defaultSiteName == null) {
72                     s_defaultSiteName = SR.GetString(SR.DefaultSiteName);
73                 }
74
75                 return s_defaultSiteName;
76             }
77         }
78
79         internal WebConfigurationHost() {
80             Type type = Type.GetType(InternalHostTypeName, true);
81             Host = (IInternalConfigHost) Activator.CreateInstance(type, true);
82         }
83
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) {
87
88             appPath = null;
89             appSiteName = null;
90             appSiteID = null;
91
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");
98                 }
99
100                 if (webLevel == WebLevel.Machine) {
101                     configPath = MachineConfigPath;
102                 }
103                 else {
104                     configPath = RootWebConfigPath;
105                 }
106             }
107             else {
108                 // Get the site name and ID
109                 if (!String.IsNullOrEmpty(site)) {
110                     configMapPath.ResolveSiteArgument(site, out appSiteName, out appSiteID);
111
112                     if (String.IsNullOrEmpty(appSiteID)) {
113                         throw new InvalidOperationException(SR.GetString(SR.Config_failed_to_resolve_site_id, site));
114                     }
115                 }
116                 else {
117                     // If site not supplied, try hosting environment first
118                     if (HostingEnvironment.IsHosted) {
119                         appSiteName = HostingEnvironment.SiteNameNoDemand;
120                         appSiteID = HostingEnvironment.SiteID;
121                     }
122
123                     // Rely on defaults if not provided in hosting environment
124                     if (String.IsNullOrEmpty(appSiteID)) {
125                         configMapPath.GetDefaultSiteNameAndID(out appSiteName, out appSiteID);
126                     }
127
128                     Debug.Assert(!String.IsNullOrEmpty(appSiteID), "No appSiteID found when site argument is null");
129                 }
130
131                 configPath = GetConfigPathFromSiteIDAndVPath(appSiteID, virtualPath);
132             }
133
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);
141
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);
149                     }
150                     else {
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;
156                         }
157                         // Otherwise, the site argument is ambiguous.
158                         else {
159                             // 
160
161                             appSiteName = null;
162                             appSiteID = null;
163                         }
164                     }
165                 }
166             }
167
168             // get appPath
169             string appPathString = null;
170             if (locationVPath != null) {
171                 appPathString = configMapPath.GetAppPathForPath(appSiteID, locationVPath.VirtualPathString);
172             }
173             else if (virtualPath != null) {
174                 appPathString = configMapPath.GetAppPathForPath(appSiteID, virtualPath.VirtualPathString);
175             }
176
177             if (appPathString != null) {
178                 appPath = VirtualPath.Create(appPathString);
179             }
180         }
181
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;
187             }
188             else if (fileMap != null) {
189                 _configMapPath = new UserMapPath(fileMap);
190             }
191             else if (HostingEnvironment.IsHosted) {
192                 _configMapPath = HostingPreferredMapPath.GetInstance();
193             }
194             else {
195                 _configMapPath = IISMapPath.GetInstance();
196             }
197
198             // see if it supports IConfigMapPath2
199             _configMapPath2 = _configMapPath as IConfigMapPath2;
200         }
201
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];
209
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");
216                 }
217             }
218
219             Debug.Assert(configMapPath == null || useConfigMapPath, "non-null configMapPath without useConfigMapPath == true");
220
221             Host.Init(configRoot, hostInitParams);
222
223             ChooseAndInitConfigMapPath(useConfigMapPath, configMapPath, fileMap);
224
225             appPath = UrlPath.RemoveSlashFromPathIfNeeded(appPath);
226             _appPath = VirtualPath.CreateAbsoluteAllowNull(appPath);
227             _appSiteName = appSiteName;
228             _appSiteID = appSiteID;
229
230             if (!String.IsNullOrEmpty(_appSiteID) && _appPath != null) {
231                 _appConfigPath = GetConfigPathFromSiteIDAndVPath(_appSiteID, _appPath);
232             }
233
234 #if DBG
235             _inited = true;
236 #endif
237         }
238
239         public override void InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath,
240                         IInternalConfigRoot configRoot, params object[] hostInitConfigurationParams) {
241
242
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];
247
248             if (locationSubPath == null) {
249                 locationSubPath = (string)                              hostInitConfigurationParams[4];
250             }
251
252             Host.Init(configRoot, hostInitConfigurationParams);
253
254              // Choose the implementation of IConfigMapPath.
255             ChooseAndInitConfigMapPath(false, null, fileMap);
256
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);
260
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)) {
267                 string finalSiteID;
268                 VirtualPath finalPath;
269                 GetSiteIDAndVPathFromConfigPath(configPath, out finalSiteID, out finalPath);
270
271                 string physicalPath;
272
273                 // attempt to use IConfigMapPath2 if provider supports it
274                 if (null != _configMapPath2) {
275                     physicalPath = _configMapPath2.MapPath(finalSiteID, finalPath);
276                 }
277                 else {
278                     physicalPath = _configMapPath.MapPath(finalSiteID, finalPath.VirtualPathString);
279                 }
280
281                 if (String.IsNullOrEmpty(physicalPath)) {
282                     throw new ArgumentOutOfRangeException("site");
283                 }
284             }
285
286 #if DBG
287             _inited = true;
288 #endif
289         }
290
291
292         //
293         // Utilities to parse config path
294         //
295         // In both WHIDBEY and ORCAS, Path has the format:
296         //          MACHINE/WEBROOT/[Site ID]/[Path Component]/[Path Component]/...
297         //
298
299         static internal bool IsMachineConfigPath(string configPath) {
300             return configPath.Length == MachineConfigPath.Length;
301         }
302
303         static internal bool IsRootWebConfigPath(string configPath) {
304             return configPath.Length == RootWebConfigPath.Length;
305         }
306
307         // Does the configPath represent a virtual path?
308         static internal bool IsVirtualPathConfigPath(string configPath) {
309             return configPath.Length > RootWebConfigPath.Length;
310         }
311
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];
318
319                 if (first == '/' || first == '\\' || last == '/' || last == '\\') {
320                     return false;
321                 }
322             }
323
324             return true;
325         }
326
327         // Return the virtual path from the configPath.
328         static internal string VPathFromConfigPath(string configPath) {
329             if (!IsVirtualPathConfigPath(configPath))
330                 return null;
331
332             // Return the path part after [SiteName]
333             int indexStart = RootWebConfigPath.Length + 1;
334             int indexVPath = configPath.IndexOf(PathSeparator, indexStart);
335             if (indexVPath == -1) {
336                 return "/";
337             }
338
339             return configPath.Substring(indexVPath);
340         }
341
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);
347         }
348
349         static internal void GetSiteIDAndVPathFromConfigPath(string configPath, out string siteID, out VirtualPath vpath) {
350             if (!IsVirtualPathConfigPath(configPath)) {
351                 siteID = null;
352                 vpath = null;
353                 return;
354             }
355
356             int indexStart = RootWebConfigPath.Length + 1;
357             int indexVPath = configPath.IndexOf(PathSeparator, indexStart);
358             int length;
359             if (indexVPath == -1) {
360                 length = configPath.Length - indexStart;
361             }
362             else {
363                 length = indexVPath - indexStart;
364             }
365
366             siteID = configPath.Substring(indexStart, length);
367             if (indexVPath == -1) {
368                 vpath = VirtualPath.RootVirtualPath;
369             }
370             else {
371                 vpath = VirtualPath.CreateAbsolute(configPath.Substring(indexVPath));
372             }
373         }
374
375         [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
376         string IInternalConfigWebHost.GetConfigPathFromSiteIDAndVPath(string siteID, string vpath) {
377             return WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(
378                 siteID, VirtualPath.CreateAbsoluteAllowNull(vpath));
379         }
380
381         static internal string GetConfigPathFromSiteIDAndVPath(string siteID, VirtualPath vpath) {
382 #if DBG
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");
386 #endif
387
388             if (vpath == null || string.IsNullOrEmpty(siteID)) {
389                 return RootWebConfigPath;
390             }
391
392             string virtualPath = vpath.VirtualPathStringNoTrailingSlash.ToLower(CultureInfo.InvariantCulture);
393             string configPath = (siteID == DefaultSiteID) ? RootWebConfigPathAndDefaultSiteID : RootWebConfigPathAndPathSeparator + siteID;
394             if (virtualPath.Length > 1) {
395                 configPath += virtualPath;
396             }
397             return configPath;
398         }
399
400         static internal string CombineConfigPath(string parentConfigPath, string childConfigPath) {
401             if (String.IsNullOrEmpty(parentConfigPath)) {
402                 return childConfigPath;
403             }
404
405             if (String.IsNullOrEmpty(childConfigPath)) {
406                 return parentConfigPath;
407             }
408
409             return parentConfigPath + PathSeparator + childConfigPath;
410         }
411
412         public override bool IsConfigRecordRequired(string configPath) {
413             // machine.config and root web.config are required records
414             if (!IsVirtualPathConfigPath(configPath))
415                 return true;
416
417             // find the physical translation
418             string siteID;
419             VirtualPath path;
420             GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out path);
421
422             string physicalPath;
423
424             // attempt to use fast path VirtualPath interface
425             if (null != _configMapPath2) {
426                 physicalPath = _configMapPath2.MapPath(siteID, path);
427             }
428             else {
429                 physicalPath = _configMapPath.MapPath(siteID, path.VirtualPathString);
430             }
431
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)
436                 return true;
437
438             // vpaths that correspond to directories are required
439             return FileUtil.DirectoryExists(physicalPath, true);
440         }
441
442         // stream support
443         public override string GetStreamName(string configPath) {
444             if (IsMachineConfigPath(configPath)) {
445                 return !string.IsNullOrEmpty(_machineConfigFile) ? _machineConfigFile : _configMapPath.GetMachineConfigFilename();
446             }
447             if (IsRootWebConfigPath(configPath)) {
448                 return !string.IsNullOrEmpty(_rootWebConfigFile) ? _rootWebConfigFile : _configMapPath.GetRootWebConfigFilename();
449             }
450             else {
451                 string siteID;
452                 VirtualPath path;
453                 GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out path);
454
455                 string directory, baseName;
456
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);
461                 }
462                 else {
463                     _configMapPath.GetPathConfigFilename(siteID, path.VirtualPathString, out directory, out baseName);
464                 }
465                 if (directory == null)
466                     return null;
467
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
477                     // return null.
478
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);
483                 }
484
485                 return null;
486             }
487         }
488
489         [FileIOPermissionAttribute(SecurityAction.Assert, AllFiles=FileIOPermissionAccess.PathDiscovery)]
490         private string CombineAndValidatePath(string directory, string baseName) {
491             try {
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);
496                 return path;
497             }
498             catch (PathTooLongException) {
499                 return null;
500             }
501             catch (NotSupportedException) {
502                 return null;
503             }
504             catch (ArgumentException) {
505                 return null;
506             }
507         }
508
509         // change notification support - runtime only
510         public override bool SupportsChangeNotifications {
511             get {return true;}
512         }
513
514         private Hashtable FileChangeCallbacks {
515             get {
516                 if (_fileChangeCallbacks == null) {
517                     _fileChangeCallbacks = new Hashtable(StringComparer.OrdinalIgnoreCase);
518                 }
519
520                 return _fileChangeCallbacks;
521             }
522         }
523
524         public override object StartMonitoringStreamForChanges(string streamName, StreamChangeCallback callback) {
525             WebConfigurationHostFileChange wrapper;
526
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.
529             lock (this) {
530                 wrapper = new WebConfigurationHostFileChange(callback);
531                 ArrayList list = (ArrayList) FileChangeCallbacks[streamName];
532                 if (list == null) {
533                     list = new ArrayList(1);
534                     FileChangeCallbacks.Add(streamName, list);
535                 }
536
537                 list.Add(wrapper);
538             }
539
540             HttpRuntime.FileChangesMonitor.StartMonitoringFile(
541                     streamName, new FileChangeEventHandler(wrapper.OnFileChanged));
542
543             return wrapper;
544         }
545
546         public override void StopMonitoringStreamForChanges(string streamName, StreamChangeCallback callback) {
547             WebConfigurationHostFileChange wrapper = null;
548             lock (this) {
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)) {
553                         wrapper = item;
554                         list.RemoveAt(i);
555                         if (list.Count == 0) {
556                             FileChangeCallbacks.Remove(streamName);
557                         }
558                         break;
559                     }
560                 }
561             }
562
563             HttpRuntime.FileChangesMonitor.StopMonitoringFile(streamName, wrapper);
564         }
565
566         public override bool IsDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition) {
567             switch (allowDefinition) {
568                 case ConfigurationAllowDefinition.MachineOnly:
569                     return configPath.Length <= MachineConfigPath.Length;
570
571                 case ConfigurationAllowDefinition.MachineToWebRoot:
572                     return configPath.Length <= RootWebConfigPath.Length;
573
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);
580
581                 // MachineToLocalUser does not current have any definition restrictions
582                 case ConfigurationAllowDefinition.Everywhere:
583                     return true;
584
585                 default:
586                     // If we have extended ConfigurationAllowDefinition
587                     // make sure to update this switch accordingly
588                     throw ExceptionUtil.UnexpectedError("WebConfigurationHost::IsDefinitionAllowed");
589             }
590         }
591
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);
597
598                     case ConfigurationAllowDefinition.MachineToWebRoot:
599                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_allow_definition_error_webroot), errorInfo.Filename, errorInfo.LineNumber);
600
601                     case ConfigurationAllowDefinition.MachineToApplication:
602                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_allow_definition_error_application), errorInfo.Filename, errorInfo.LineNumber);
603
604                     default:
605                         // If we have extended ConfigurationAllowDefinition
606                         // make sure to update this switch accordingly
607                         throw ExceptionUtil.UnexpectedError("WebConfigurationHost::VerifyDefinitionAllowed");
608                 }
609             }
610         }
611
612         private WebApplicationLevel GetPathLevel(string configPath) {
613             if (!IsVirtualPathConfigPath(configPath))
614                 return WebApplicationLevel.AboveApplication;
615
616 #if DBG
617             Debug.Assert(_inited, "_inited");
618 #endif
619
620             // Disable handling of path level when we don't have an application path.
621             if (_appPath == null)
622                 return WebApplicationLevel.AboveApplication;
623
624             string siteID;
625             VirtualPath path;
626             GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out path);
627             if (!StringUtil.EqualsIgnoreCase(_appSiteID, siteID))
628                 return WebApplicationLevel.AboveApplication;
629
630             if (_appPath == path)
631                 return WebApplicationLevel.AtApplication;
632
633             if (UrlPath.IsEqualOrSubpath(_appPath.VirtualPathString, path.VirtualPathString))
634                 return WebApplicationLevel.BelowApplication;
635
636             return WebApplicationLevel.AboveApplication;
637         }
638
639         // path support
640         public override bool SupportsPath {
641             get {
642                 return true;
643             }
644         }
645
646         public override bool SupportsLocation {
647             get {
648                 return true;
649             }
650         }
651
652         public override bool IsAboveApplication(string configPath) {
653             return GetPathLevel(configPath) == WebApplicationLevel.AboveApplication;
654         }
655
656         static internal string GetConfigPathFromLocationSubPathBasic(string configPath, string locationSubPath) {
657             string locationConfigPath;
658
659             if (IsVirtualPathConfigPath(configPath)) {
660                 locationConfigPath = CombineConfigPath(configPath, locationSubPath);
661             }
662             else {
663                 // Location subpaths only apply to virtual paths, not config file roots.
664                 locationConfigPath = CombineConfigPath(RootWebConfigPath, locationSubPath);
665             }
666
667             return locationConfigPath;
668         }
669
670         public override string GetConfigPathFromLocationSubPath(string configPath, string locationSubPath) {
671 #if DBG
672             Debug.Assert(_inited, "_inited");
673 #endif
674
675             string locationConfigPath;
676
677             if (IsVirtualPathConfigPath(configPath)) {
678                 locationConfigPath = CombineConfigPath(configPath, locationSubPath);
679             }
680             else {
681                 string siteID = null;
682
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.
687                 string site;
688                 VirtualPath virtualPath;
689                 int firstSlash = locationSubPath.IndexOf(PathSeparator);
690                 if (firstSlash < 0) {
691                     site = locationSubPath;
692                     virtualPath = VirtualPath.RootVirtualPath;
693                 }
694                 else {
695                     site = locationSubPath.Substring(0, firstSlash);
696                     virtualPath = VirtualPath.CreateAbsolute(locationSubPath.Substring(firstSlash));
697                 }
698
699                 if (StringUtil.EqualsIgnoreCase(site, _appSiteID) || StringUtil.EqualsIgnoreCase(site, _appSiteName)) {
700                     siteID = _appSiteID;
701                 }
702                 else {
703                     siteID = site;
704                 }
705
706                 locationConfigPath = GetConfigPathFromSiteIDAndVPath(siteID, virtualPath);
707             }
708
709             return locationConfigPath;
710         }
711
712         public override bool IsLocationApplicable(string configPath) {
713             return IsVirtualPathConfigPath(configPath);
714         }
715
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;
721             }
722         }
723
724         // we trust root config files - admins settings do not have security restrictions.
725         public override bool IsTrustedConfigPath(string configPath) {
726             return !IsVirtualPathConfigPath(configPath);
727         }
728
729         public override bool IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord) {
730             if (HostingEnvironment.IsHosted) {
731                 return HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted);
732             }
733             else {
734                 return Host.IsFullTrustSectionWithoutAptcaAllowed(configRecord);
735             }
736         }
737
738         public override void GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady) {
739             StaticGetRestrictedPermissions(configRecord, out permissionSet, out isHostReady);
740         }
741
742         public override IDisposable Impersonate() {
743             return new ApplicationImpersonationContext();
744         }
745
746         // prefetch support
747         public override bool PrefetchAll(string configPath, string streamName) {
748             return !IsMachineConfigPath(configPath);
749         }
750
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] == '/')) {
755
756                 return true;
757             }
758
759             if (String.IsNullOrEmpty(sectionGroupName) && sectionName == "system.codedom")
760                 return true;
761
762             return false;
763         }
764
765         // context support
766         public override object CreateDeprecatedConfigContext(string configPath) {
767             return new HttpConfigurationContext(VPathFromConfigPath(configPath));
768         }
769
770         // CreateConfigurationContext
771         //
772         // Create the ConfigurationContext for ConfigurationElement's
773         //
774         // Parameters:
775         //   configPath      - Config Path we are quering for
776         //   locationSubPath - Location SubPath
777         //
778         public override object CreateConfigurationContext(string configPath, string locationSubPath)
779         {
780             string              path;
781             WebApplicationLevel pathLevel;
782
783             path      = VPathFromConfigPath(configPath);
784             pathLevel = GetPathLevel(configPath);
785
786             return new WebContext( pathLevel,         // PathLevel
787                                    _appSiteName,      // Site
788                                    VirtualPath.GetVirtualPathString(_appPath),          // AppPath
789                                    path,              // Path
790                                    locationSubPath,   // LocationSubPath
791                                    _appConfigPath);   // e.g., "machine/webroot/2/approot"
792         }
793
794         // Type name support
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);
799         }
800
801         public override string GetConfigTypeName(Type t) {
802             return BuildManager.GetNormalizedTypeName(t);
803         }
804
805         // IsApplication
806         //
807         // Given a config Path, is it the Path for an application?
808         //
809         private bool IsApplication(string configPath) {
810             VirtualPath appPath;
811             string siteID;
812             VirtualPath vpath;
813
814             // Break up into siteID and vpath
815             GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out vpath);
816
817             // Retrieve appPath for this
818             if (null != _configMapPath2) {
819                 appPath = _configMapPath2.GetAppPathForPath(siteID, vpath);
820             }
821             else {
822                 appPath = VirtualPath.CreateAllowNull(_configMapPath.GetAppPathForPath(siteID, vpath.VirtualPathString));
823             }
824
825             return (appPath == vpath);
826         }
827
828         // Get the factory used to create and initialize Configuration objects.
829         static internal IInternalConfigConfigurationFactory ConfigurationFactory {
830             [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.MemberAccess)]
831             get {
832                 if (s_configurationFactory == null) {
833                     Type type = Type.GetType(InternalConfigConfigurationFactoryTypeName, true);
834                     s_configurationFactory = (IInternalConfigConfigurationFactory) Activator.CreateInstance(type, true);
835                 }
836
837                 return s_configurationFactory;
838             }
839         }
840
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) {
846
847             Configuration configuration;
848
849             if (!IsValidSiteArgument(site)) {
850                 throw ExceptionUtil.ParameterInvalid("site");
851             }
852
853             locationSubPath = ConfigurationFactory.NormalizeLocationSubPath(locationSubPath, null);
854
855             bool isRemote = !String.IsNullOrEmpty(server)
856                 && 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);
861
862
863             if (isRemote) {
864                 configuration = ConfigurationFactory.Create(typeof(RemoteWebConfigurationHost),
865                     webLevel, null, VirtualPath.GetVirtualPathString(path), site, locationSubPath, server, userName, password, tokenHandle);
866             }
867             else {
868                  if (String.IsNullOrEmpty(server)) {
869                     if (!String.IsNullOrEmpty(userName))
870                         throw ExceptionUtil.ParameterInvalid("userName");
871
872                     if (!String.IsNullOrEmpty(password))
873                         throw ExceptionUtil.ParameterInvalid("password");
874
875                     if (tokenHandle != (IntPtr) 0)
876                         throw ExceptionUtil.ParameterInvalid("tokenHandle");
877                 }
878
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();
883                 }
884
885                 WebConfigurationFileMap webFileMap = fileMap as WebConfigurationFileMap;
886                 if (webFileMap != null && !String.IsNullOrEmpty(site)) {
887                     webFileMap.Site = site;
888                 }
889
890                 configuration = ConfigurationFactory.Create(typeof(WebConfigurationHost),
891                     webLevel, fileMap, VirtualPath.GetVirtualPathString(path), site, locationSubPath );
892              }
893
894             return configuration;
895         }
896
897
898         private static string GetMachineConfigPathFromTargetFrameworkMoniker(string moniker) {
899             TargetDotNetFrameworkVersion ver = GetTargetFrameworkVersionEnumFromMoniker(moniker);
900             if (ver == TargetDotNetFrameworkVersion.VersionLatest)
901                 return null;
902
903             string machineConfig = ToolLocationHelper.GetPathToDotNetFrameworkFile(@"config\machine.config", ver);
904             new FileIOPermission(FileIOPermissionAccess.PathDiscovery, machineConfig).Demand();
905             return machineConfig;
906         }
907
908         private static TargetDotNetFrameworkVersion GetTargetFrameworkVersionEnumFromMoniker(string moniker)
909         {
910             // 
911
912             if (moniker.Contains("3.5") || moniker.Contains("3.0") || moniker.Contains("2.0") ) {
913                 return TargetDotNetFrameworkVersion.Version20;
914             }
915             return TargetDotNetFrameworkVersion.VersionLatest;
916         }
917     }
918 }