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