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