Reverse previous changes
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / WebConfigurationManager.cs
1 //
2 // System.Web.Configuration.WebConfigurationManager.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //      Chris Toshok (toshok@ximian.com)
7 //      Marek Habersack <mhabersack@novell.com>
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
29 //
30
31 #if NET_2_0
32
33 using System;
34 using System.IO;
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Collections.Specialized;
38 using System.Reflection;
39 #if MONOWEB_DEP
40 using Mono.Web.Util;
41 #endif
42 using System.Xml;
43 using System.Configuration;
44 using System.Configuration.Internal;
45 using _Configuration = System.Configuration.Configuration;
46 using System.Web.Util;
47 using System.Threading;
48 using System.Web.Hosting;
49
50 namespace System.Web.Configuration {
51
52         public static class WebConfigurationManager
53         {
54                 sealed class ConfigPath 
55                 {
56                         public string Path;
57                         public bool InAnotherApp;
58
59                         public ConfigPath (string path, bool inAnotherApp)
60                         {
61                                 this.Path = path;
62                                 this.InAnotherApp = inAnotherApp;
63                         }
64                 }
65                 
66                 const int SAVE_LOCATIONS_CHECK_INTERVAL = 6000; // milliseconds
67                 const int SECTION_CACHE_LOCK_TIMEOUT = 200; // milliseconds
68
69                 static readonly char[] pathTrimChars = { '/' };
70                 static readonly object suppressAppReloadLock = new object ();
71                 static readonly object saveLocationsCacheLock = new object ();
72                 
73                 // See comment for the cacheLock field at top of System.Web.Caching/Cache.cs
74                 static readonly ReaderWriterLockSlim sectionCacheLock;
75                 
76 #if !TARGET_J2EE
77                 static IInternalConfigConfigurationFactory configFactory;
78                 static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
79                 static Dictionary <int, object> sectionCache = new Dictionary <int, object> ();
80                 static Hashtable configPaths = Hashtable.Synchronized (new Hashtable ());
81                 static bool suppressAppReload;
82 #else
83                 const string AppSettingsKey = "WebConfigurationManager.AppSettings";
84                 
85                 static internal IInternalConfigConfigurationFactory configFactory
86                 {
87                         get{
88                                 IInternalConfigConfigurationFactory factory = (IInternalConfigConfigurationFactory)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory");
89                                 if (factory == null){
90                                         lock (AppDomain.CurrentDomain){
91                                                 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory.initialized");
92                                                 if (initialized == null){
93                                                         PropertyInfo prop = typeof(ConfigurationManager).GetProperty("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
94                                                         if (prop != null){
95                                                                 factory = prop.GetValue(null, null) as IInternalConfigConfigurationFactory;
96                                                                 configFactory = factory;
97                                                         }
98                                                 }
99                                         }
100                                 }
101                                 return factory != null ? factory : configFactory;
102                         }
103                         set{
104                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory", value);
105                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory.initialized", true);
106                         }
107                 }
108
109                 static internal Hashtable configurations
110                 {
111                         get{
112                                 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations");
113                                 if (table == null){
114                                         lock (AppDomain.CurrentDomain){
115                                                 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations.initialized");
116                                                 if (initialized == null){
117                                                         table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
118                                                         configurations = table;
119                                                 }
120                                         }
121                                 }
122                                 return table != null ? table : configurations;
123
124                         }
125                         set{
126                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations", value);
127                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations.initialized", true);
128                         }
129                 }
130
131                 static Dictionary <int, object> sectionCache
132                 {
133                         get
134                         {
135                                 Dictionary <int, object> sectionCache = AppDomain.CurrentDomain.GetData ("sectionCache") as Dictionary <int, object>;
136                                 if (sectionCache == null) {
137                                         sectionCache = new Dictionary <int, object> ();
138                                         AppDomain.CurrentDomain.SetData ("sectionCache", sectionCache);
139                                 }
140                                 return sectionCache;
141                         }
142                         set
143                         {
144                                 AppDomain.CurrentDomain.SetData ("sectionCache", value);
145                         }
146                 }
147
148                 static internal Hashtable configPaths
149                 {
150                         get{
151                                 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configPaths");
152                                 if (table == null){
153                                         lock (AppDomain.CurrentDomain){
154                                                 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configPaths.initialized");
155                                                 if (initialized == null){
156                                                         table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
157                                                         configPaths = table;
158                                                 }
159                                         }
160                                 }
161                                 return table != null ? table : configPaths;
162
163                         }
164                         set{
165                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configPaths", value);
166                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configPaths.initialized", true);
167                         }
168                 }
169 #endif
170                 static Dictionary <string, DateTime> saveLocationsCache;
171                 static Timer saveLocationsTimer;
172                 
173                 static ArrayList extra_assemblies = null;
174                 static internal ArrayList ExtraAssemblies {
175                         get {
176                                 if (extra_assemblies == null)
177                                         extra_assemblies = new ArrayList();
178                                 return extra_assemblies;
179                         }
180                 }
181
182                 static bool hasConfigErrors = false;
183                 static object hasConfigErrorsLock = new object ();
184                 static internal bool HasConfigErrors {
185                         get {
186                                 lock (hasConfigErrorsLock) {
187                                         return hasConfigErrors;
188                                 }
189                         }
190                 }
191                 
192                 static WebConfigurationManager ()
193                 {
194                         configFactory = ConfigurationManager.ConfigurationFactory;
195                         _Configuration.SaveStart += ConfigurationSaveHandler;
196                         _Configuration.SaveEnd += ConfigurationSaveHandler;
197                         
198                         // Part of fix for bug #491531
199                         Type type = Type.GetType ("System.Configuration.CustomizableFileSettingsProvider, System", false);
200                         if (type != null) {
201                                 FieldInfo fi = type.GetField ("webConfigurationFileMapType", BindingFlags.Static | BindingFlags.NonPublic);
202                                 if (fi != null && fi.FieldType == Type.GetType ("System.Type"))
203                                         fi.SetValue (null, typeof (ApplicationSettingsConfigurationFileMap));
204                         }
205
206                         sectionCacheLock = new ReaderWriterLockSlim ();
207                 }
208
209                 static void ReenableWatcherOnConfigLocation (object state)
210                 {
211                         string path = state as string;
212                         if (String.IsNullOrEmpty (path))
213                                 return;
214
215                         DateTime lastWrite;
216                         lock (saveLocationsCacheLock) {
217                                 if (!saveLocationsCache.TryGetValue (path, out lastWrite))
218                                         lastWrite = DateTime.MinValue;
219                         }
220
221                         DateTime now = DateTime.Now;
222                         if (lastWrite == DateTime.MinValue || now.Subtract (lastWrite).TotalMilliseconds >= SAVE_LOCATIONS_CHECK_INTERVAL) {
223                                 saveLocationsTimer.Dispose ();
224                                 saveLocationsTimer = null;
225                                 HttpApplicationFactory.EnableWatcher (VirtualPathUtility.RemoveTrailingSlash (HttpRuntime.AppDomainAppPath), "?eb.?onfig");
226                         } else
227                                 saveLocationsTimer.Change (SAVE_LOCATIONS_CHECK_INTERVAL, SAVE_LOCATIONS_CHECK_INTERVAL);
228                 }
229                 
230                 static void ConfigurationSaveHandler (_Configuration sender, ConfigurationSaveEventArgs args)
231                 {
232                         try {
233                                 sectionCacheLock.EnterWriteLock ();
234                                 sectionCache.Clear ();
235                         } finally {
236                                 sectionCacheLock.ExitWriteLock ();
237                         }
238                         
239                         lock (suppressAppReloadLock) {
240                                 string rootConfigPath = WebConfigurationHost.GetWebConfigFileName (HttpRuntime.AppDomainAppPath);
241                                 if (String.Compare (args.StreamPath, rootConfigPath, StringComparison.OrdinalIgnoreCase) == 0) {
242                                         SuppressAppReload (args.Start);
243                                         if (args.Start) {
244                                                 HttpApplicationFactory.DisableWatcher (VirtualPathUtility.RemoveTrailingSlash (HttpRuntime.AppDomainAppPath), "?eb.?onfig");
245
246                                                 lock (saveLocationsCacheLock) {
247                                                         if (saveLocationsCache == null)
248                                                                 saveLocationsCache = new Dictionary <string, DateTime> (StringComparer.Ordinal);
249                                                         if (saveLocationsCache.ContainsKey (rootConfigPath))
250                                                                 saveLocationsCache [rootConfigPath] = DateTime.Now;
251                                                         else
252                                                                 saveLocationsCache.Add (rootConfigPath, DateTime.Now);
253
254                                                         if (saveLocationsTimer == null)
255                                                                 saveLocationsTimer = new Timer (ReenableWatcherOnConfigLocation,
256                                                                                                 rootConfigPath,
257                                                                                                 SAVE_LOCATIONS_CHECK_INTERVAL,
258                                                                                                 SAVE_LOCATIONS_CHECK_INTERVAL);
259                                                 }
260                                         }
261                                 }
262                         }
263                 }
264                 
265                 public static _Configuration OpenMachineConfiguration ()
266                 {
267                         return ConfigurationManager.OpenMachineConfiguration ();
268                 }
269                 
270                 [MonoLimitation ("locationSubPath is not handled")]
271                 public static _Configuration OpenMachineConfiguration (string locationSubPath)
272                 {
273                         return OpenMachineConfiguration ();
274                 }
275
276                 [MonoLimitation("Mono does not support remote configuration")]
277                 public static _Configuration OpenMachineConfiguration (string locationSubPath,
278                                                                        string server)
279                 {
280                         if (server == null)
281                                 return OpenMachineConfiguration (locationSubPath);
282
283                         throw new NotSupportedException ("Mono doesn't support remote configuration");
284                 }
285
286                 [MonoLimitation("Mono does not support remote configuration")]
287                 public static _Configuration OpenMachineConfiguration (string locationSubPath,
288                                                                        string server,
289                                                                        IntPtr userToken)
290                 {
291                         if (server == null)
292                                 return OpenMachineConfiguration (locationSubPath);
293                         throw new NotSupportedException ("Mono doesn't support remote configuration");
294                 }
295
296                 [MonoLimitation("Mono does not support remote configuration")]
297                 public static _Configuration OpenMachineConfiguration (string locationSubPath,
298                                                                        string server,
299                                                                        string userName,
300                                                                        string password)
301                 {
302                         if (server == null)
303                                 return OpenMachineConfiguration (locationSubPath);
304                         throw new NotSupportedException ("Mono doesn't support remote configuration");
305                 }
306
307                 public static _Configuration OpenWebConfiguration (string path)
308                 {
309                         return OpenWebConfiguration (path, null, null, null, null, null);
310                 }
311                 
312                 public static _Configuration OpenWebConfiguration (string path, string site)
313                 {
314                         return OpenWebConfiguration (path, site, null, null, null, null);
315                 }
316                 
317                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath)
318                 {
319                         return OpenWebConfiguration (path, site, locationSubPath, null, null, null);
320                 }
321
322                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server)
323                 {
324                         return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
325                 }
326
327                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, IntPtr userToken)
328                 {
329                         return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
330                 }
331                 
332                 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
333                 {
334                         return OpenWebConfiguration (path, site, locationSubPath, server, null, null, false);
335                 }
336
337                 static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password, bool fweb)
338                 {
339                         if (String.IsNullOrEmpty (path))
340                                 path = "/";
341
342                         bool inAnotherApp = false;
343                         if (!fweb && !String.IsNullOrEmpty (path))
344                                 path = FindWebConfig (path, out inAnotherApp);
345
346                         string confKey = path + site + locationSubPath + server + userName + password;
347                         _Configuration conf = null;
348                         conf = (_Configuration) configurations [confKey];
349                         if (conf == null) {
350                                 try {
351                                         conf = ConfigurationFactory.Create (typeof (WebConfigurationHost), null, path, site, locationSubPath, server, userName, password, inAnotherApp);
352                                         configurations [confKey] = conf;
353                                 } catch (Exception ex) {
354                                         lock (hasConfigErrorsLock) {
355                                                 hasConfigErrors = true;
356                                         }
357                                         throw ex;
358                                 }
359                         }
360                         return conf;
361                 }
362
363                 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path)
364                 {
365                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path);
366                 }
367                 
368                 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site)
369                 {
370                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site);
371                 }
372                 
373                 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site, string locationSubPath)
374                 {
375                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site, locationSubPath);
376                 }
377                 
378                 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap)
379                 {
380                         return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap);
381                 }
382
383                 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap,
384                                                                              string locationSubPath)
385                 {
386                         return OpenMappedMachineConfiguration (fileMap);
387                 }
388
389                 internal static object SafeGetSection (string sectionName, Type configSectionType)
390                 {
391                         try {
392                                 return GetSection (sectionName);
393                         } catch (Exception) {
394                                 if (configSectionType != null)
395                                         return Activator.CreateInstance (configSectionType);
396                                 return null;
397                         }
398                 }
399                 
400                 internal static object SafeGetSection (string sectionName, string path, Type configSectionType)
401                 {
402                         try {
403                                 return GetSection (sectionName, path);
404                         } catch (Exception) {
405                                 if (configSectionType != null)
406                                         return Activator.CreateInstance (configSectionType);
407                                 return null;
408                         }
409                 }
410                 
411                 public static object GetSection (string sectionName)
412                 {
413                         HttpContext context = HttpContext.Current;
414                         return GetSection (sectionName, GetCurrentPath (context), context);
415                 }
416
417                 public static object GetSection (string sectionName, string path)
418                 {
419                         return GetSection (sectionName, path, HttpContext.Current);
420                 }
421
422                 static bool LookUpLocation (string relativePath, ref _Configuration defaultConfiguration)
423                 {
424                         if (String.IsNullOrEmpty (relativePath))
425                                 return false;
426
427                         _Configuration cnew = defaultConfiguration.FindLocationConfiguration (relativePath, defaultConfiguration);
428                         if (cnew == defaultConfiguration)
429                                 return false;
430
431                         defaultConfiguration = cnew;
432                         return true;
433                 }
434                 
435                 internal static object GetSection (string sectionName, string path, HttpContext context)
436                 {
437                         if (String.IsNullOrEmpty (sectionName))
438                                 return null;
439                         
440                         _Configuration c = OpenWebConfiguration (path, null, null, null, null, null, false);
441                         string configPath = c.ConfigPath;
442                         int baseCacheKey = 0;
443                         int cacheKey;
444                         bool pathPresent = !String.IsNullOrEmpty (path);
445                         string locationPath = null;
446
447                         if (pathPresent)
448                                 locationPath = "location_" + path;
449                         
450                         baseCacheKey = sectionName.GetHashCode ();
451                         if (configPath != null)
452                                 baseCacheKey ^= configPath.GetHashCode ();
453                         
454                         try {
455                                 sectionCacheLock.EnterReadLock ();
456                                 
457                                 object o;
458                                 if (pathPresent) {
459                                         cacheKey = baseCacheKey ^ locationPath.GetHashCode ();
460                                         if (sectionCache.TryGetValue (cacheKey, out o))
461                                                 return o;
462                                 
463                                         cacheKey = baseCacheKey ^ path.GetHashCode ();
464                                         if (sectionCache.TryGetValue (cacheKey, out o))
465                                                 return o;
466                                 }
467                                 
468                                 if (sectionCache.TryGetValue (baseCacheKey, out o))
469                                         return o;
470                         } finally {
471                                 sectionCacheLock.ExitReadLock ();
472                         }
473
474                         string cachePath = null;
475                         if (pathPresent) {
476                                 string relPath;
477                                 
478                                 if (VirtualPathUtility.IsRooted (path)) {
479                                         if (path [0] == '~')
480                                                 relPath = path.Length > 1 ? path.Substring (2) : String.Empty;
481                                         else if (path [0] == '/')
482                                                 relPath = path.Substring (1);
483                                         else
484                                                 relPath = path;
485                                 } else
486                                         relPath = path;
487
488                                 HttpRequest req = context != null ? context.Request : null;
489                                 if (req != null) {
490                                         string vdir = VirtualPathUtility.GetDirectory (req.PathNoValidation);
491                                         if (vdir != null) {
492                                                 vdir = vdir.TrimEnd (pathTrimChars);
493                                                 if (String.Compare (c.ConfigPath, vdir, StringComparison.Ordinal) != 0 && LookUpLocation (vdir.Trim (pathTrimChars), ref c))
494                                                         cachePath = path;
495                                         }
496                                 }
497                                 
498                                 if (LookUpLocation (relPath, ref c))
499                                         cachePath = locationPath;
500                                 else
501                                         cachePath = path;
502                         }
503
504                         ConfigurationSection section = c.GetSection (sectionName);
505                         if (section == null)
506                                 return null;
507
508 #if TARGET_J2EE
509                         object value = get_runtime_object.Invoke (section, new object [0]);
510                         if (String.CompareOrdinal ("appSettings", sectionName) == 0) {
511                                 NameValueCollection collection;
512                                 collection = new KeyValueMergedCollection (HttpContext.Current, (NameValueCollection) value);
513                                 value = collection;
514                         }
515 #else
516 #if MONOWEB_DEP
517                         object value = SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
518 #else
519                         object value = null;
520 #endif
521 #endif
522                         if (cachePath != null)
523                                 cacheKey = baseCacheKey ^ cachePath.GetHashCode ();
524                         else
525                                 cacheKey = baseCacheKey;
526                         
527                         AddSectionToCache (cacheKey, value);
528                         return value;
529                 }
530                 
531                 static string MapPath (HttpRequest req, string virtualPath)
532                 {
533                         if (req != null)
534                                 return req.MapPath (virtualPath);
535
536                         string appRoot = HttpRuntime.AppDomainAppVirtualPath;
537                         if (!String.IsNullOrEmpty (appRoot) && virtualPath.StartsWith (appRoot, StringComparison.Ordinal)) {
538                                 if (String.Compare (virtualPath, appRoot, StringComparison.Ordinal) == 0)
539                                         return HttpRuntime.AppDomainAppPath;
540                                 return UrlUtils.Combine (HttpRuntime.AppDomainAppPath, virtualPath.Substring (appRoot.Length));
541                         }
542                         
543                         return null;
544                 }
545
546                 static string GetParentDir (string rootPath, string curPath)
547                 {
548                         int len = curPath.Length - 1;
549                         if (len > 0 && curPath [len] == '/')
550                                 curPath = curPath.Substring (0, len);
551
552                         if (String.Compare (curPath, rootPath, StringComparison.Ordinal) == 0)
553                                 return null;
554                         
555                         int idx = curPath.LastIndexOf ('/');
556                         if (idx == -1)
557                                 return curPath;
558
559                         if (idx == 0)
560                                 return "/";
561                         
562                         return curPath.Substring (0, idx);
563                 }
564
565                 internal static string FindWebConfig (string path)
566                 {
567                         bool dummy;
568
569                         return FindWebConfig (path, out dummy);
570                 }
571                 
572                 internal static string FindWebConfig (string path, out bool inAnotherApp)
573                 {
574                         inAnotherApp = false;
575                         
576                         if (String.IsNullOrEmpty (path))
577                                 return path;
578                                 
579                         if (HostingEnvironment.VirtualPathProvider != null) {
580                                 if (HostingEnvironment.VirtualPathProvider.DirectoryExists (path))
581                                         path = VirtualPathUtility.AppendTrailingSlash (path);
582                         }
583                                 
584                         
585                         string rootPath = HttpRuntime.AppDomainAppVirtualPath;
586                         ConfigPath curPath;
587                         curPath = configPaths [path] as ConfigPath;
588                         if (curPath != null) {
589                                 inAnotherApp = curPath.InAnotherApp;
590                                 return curPath.Path;
591                         }
592                         
593                         HttpContext ctx = HttpContext.Current;
594                         HttpRequest req = ctx != null ? ctx.Request : null;
595                         string physPath = req != null ? VirtualPathUtility.AppendTrailingSlash (MapPath (req, path)) : null;
596                         string appDomainPath = HttpRuntime.AppDomainAppPath;
597                         
598                         if (physPath != null && appDomainPath != null && !physPath.StartsWith (appDomainPath, StringComparison.Ordinal))
599                                 inAnotherApp = true;
600                         
601                         string dir;
602                         if (inAnotherApp || path [path.Length - 1] == '/')
603                                 dir = path;
604                         else {
605                                 dir = VirtualPathUtility.GetDirectory (path, false);
606                                 if (dir == null)
607                                         return path;
608                         }
609                         
610                         curPath = configPaths [dir] as ConfigPath;
611                         if (curPath != null) {
612                                 inAnotherApp = curPath.InAnotherApp;
613                                 return curPath.Path;
614                         }
615                         
616                         if (req == null)
617                                 return path;
618
619                         curPath = new ConfigPath (path, inAnotherApp);
620                         while (String.Compare (curPath.Path, rootPath, StringComparison.Ordinal) != 0) {
621                                 physPath = MapPath (req, curPath.Path);
622                                 if (physPath == null) {
623                                         curPath.Path = rootPath;
624                                         break;
625                                 }
626
627                                 if (WebConfigurationHost.GetWebConfigFileName (physPath) != null)
628                                         break;
629                                 
630                                 curPath.Path = GetParentDir (rootPath, curPath.Path);
631                                 if (curPath.Path == null || curPath.Path == "~") {
632                                         curPath.Path = rootPath;
633                                         break;
634                                 }
635                         }
636
637                         if (String.Compare (curPath.Path, path, StringComparison.Ordinal) != 0)
638                                 configPaths [path] = curPath;
639                         else
640                                 configPaths [dir] = curPath;
641                         
642                         return curPath.Path;
643                 }
644                 
645                 static string GetCurrentPath (HttpContext ctx)
646                 {
647                         HttpRequest req = ctx != null ? ctx.Request : null;
648                         return req != null ? req.PathNoValidation : HttpRuntime.AppDomainAppVirtualPath;
649                 }
650                 
651                 internal static bool SuppressAppReload (bool newValue)
652                 {
653                         bool ret;
654                         
655                         lock (suppressAppReloadLock) {
656                                 ret = suppressAppReload;
657                                 suppressAppReload = newValue;
658                         }
659
660                         return ret;
661                 }
662                 
663                 internal static void RemoveConfigurationFromCache (HttpContext ctx)
664                 {
665                         configurations.Remove (GetCurrentPath (ctx));
666                 }
667
668 #if TARGET_J2EE || MONOWEB_DEP
669                 readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
670 #endif          
671
672                 public static object GetWebApplicationSection (string sectionName)
673                 {
674                         HttpContext ctx = HttpContext.Current;
675                         HttpRequest req = ctx != null ? ctx.Request : null;
676                         string applicationPath = req != null ? req.ApplicationPath : null;
677                         return GetSection (sectionName, String.IsNullOrEmpty (applicationPath) ? String.Empty : applicationPath);
678                 }
679
680                 public static NameValueCollection AppSettings {
681                         get { return ConfigurationManager.AppSettings; }
682                 }
683
684                 public static ConnectionStringSettingsCollection ConnectionStrings {
685                         get { return ConfigurationManager.ConnectionStrings; }
686                 }
687
688                 internal static IInternalConfigConfigurationFactory ConfigurationFactory {
689                         get { return configFactory; }
690                 }
691
692                 static void AddSectionToCache (int key, object section)
693                 {
694                         object cachedSection;
695
696                         try {
697                                 if (!sectionCacheLock.TryEnterUpgradeableReadLock (SECTION_CACHE_LOCK_TIMEOUT))
698                                         return;
699                                         
700                                 if (sectionCache.TryGetValue (key, out cachedSection) && cachedSection != null)
701                                         return;
702
703                                 try {
704                                         if (!sectionCacheLock.TryEnterWriteLock (SECTION_CACHE_LOCK_TIMEOUT))
705                                                 return;
706                                         sectionCache.Add (key, section);
707                                 } finally {
708                                         try {
709                                                 sectionCacheLock.ExitWriteLock ();
710                                         } catch (SynchronizationLockException) {
711                                                 // we can ignore it here
712                                         }
713                                 }
714                         } finally {
715                                 try {
716                                         sectionCacheLock.ExitUpgradeableReadLock ();
717                                 } catch (SynchronizationLockException) {
718                                         // we can ignore it here
719                                 }
720                         }
721                 }
722                 
723 #region stuff copied from WebConfigurationSettings
724 #if TARGET_J2EE
725                 static internal IConfigurationSystem oldConfig {
726                         get {
727                                 return (IConfigurationSystem)AppDomain.CurrentDomain.GetData("WebConfigurationManager.oldConfig");
728                         }
729                         set {
730                                 AppDomain.CurrentDomain.SetData("WebConfigurationManager.oldConfig", value);
731                         }
732                 }
733
734                 static Web20DefaultConfig config {
735                         get {
736                                 return (Web20DefaultConfig) AppDomain.CurrentDomain.GetData ("Web20DefaultConfig.config");
737                         }
738                         set {
739                                 AppDomain.CurrentDomain.SetData ("Web20DefaultConfig.config", value);
740                         }
741                 }
742
743                 static IInternalConfigSystem configSystem {
744                         get {
745                                 return (IInternalConfigSystem) AppDomain.CurrentDomain.GetData ("IInternalConfigSystem.configSystem");
746                         }
747                         set {
748                                 AppDomain.CurrentDomain.SetData ("IInternalConfigSystem.configSystem", value);
749                         }
750                 }
751 #else
752                 static internal IConfigurationSystem oldConfig;
753                 static Web20DefaultConfig config;
754                 //static IInternalConfigSystem configSystem;
755 #endif
756                 const BindingFlags privStatic = BindingFlags.NonPublic | BindingFlags.Static;
757                 static readonly object lockobj = new object ();
758
759                 internal static void Init ()
760                 {
761                         lock (lockobj) {
762                                 if (config != null)
763                                         return;
764
765                                 /* deal with the ConfigurationSettings stuff */
766                                 {
767                                         Web20DefaultConfig settings = Web20DefaultConfig.GetInstance ();
768                                         Type t = typeof (ConfigurationSettings);
769                                         MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
770                                                                                privStatic);
771
772                                         if (changeConfig == null)
773                                                 throw new ConfigurationException ("Cannot find method CCS");
774
775                                         object [] args = new object [] {settings};
776                                         oldConfig = (IConfigurationSystem)changeConfig.Invoke (null, args);
777                                         config = settings;
778
779                                         config.Init ();
780                                 }
781
782                                 /* deal with the ConfigurationManager stuff */
783                                 {
784                                         HttpConfigurationSystem system = new HttpConfigurationSystem ();
785                                         Type t = typeof (ConfigurationManager);
786                                         MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
787                                                                                privStatic);
788
789                                         if (changeConfig == null)
790                                                 throw new ConfigurationException ("Cannot find method CCS");
791
792                                         object [] args = new object [] {system};
793                                         changeConfig.Invoke (null, args);
794                                         //configSystem = system;
795                                 }
796                         }
797                 }
798         }
799
800         class Web20DefaultConfig : IConfigurationSystem
801         {
802 #if TARGET_J2EE
803                 static Web20DefaultConfig instance {
804                         get {
805                                 Web20DefaultConfig val = (Web20DefaultConfig)AppDomain.CurrentDomain.GetData("Web20DefaultConfig.instance");
806                                 if (val == null) {
807                                         val = new Web20DefaultConfig();
808                                         AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", val);
809                                 }
810                                 return val;
811                         }
812                         set {
813                                 AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", value);
814                         }
815                 }
816 #else
817                 static Web20DefaultConfig instance;
818 #endif
819
820                 static Web20DefaultConfig ()
821                 {
822                         instance = new Web20DefaultConfig ();
823                 }
824
825                 public static Web20DefaultConfig GetInstance ()
826                 {
827                         return instance;
828                 }
829
830                 public object GetConfig (string sectionName)
831                 {
832                         object o = WebConfigurationManager.GetWebApplicationSection (sectionName);
833
834                         if (o == null || o is IgnoreSection) {
835                                 /* this can happen when the section
836                                  * handler doesn't subclass from
837                                  * ConfigurationSection.  let's be
838                                  * nice and try to load it using the
839                                  * 1.x style routines in case there's
840                                  * a 1.x section handler registered
841                                  * for it.
842                                  */
843                                 object o1 = WebConfigurationManager.oldConfig.GetConfig (sectionName);
844                                 if (o1 != null)
845                                         return o1;
846                         }
847
848                         return o;
849                 }
850
851                 public void Init ()
852                 {
853                         // nothing. We need a context.
854                 }
855         }
856 #endregion
857 }
858
859 #endif