Merge pull request #5014 from vkargov/vk-kasha
[mono.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / WebConfigurationHost.cs
1 //
2 // System.Web.Configuration.WebConfigurationHost.cs
3 //
4 // Authors:
5 //  Lluis Sanchez Gual (lluis@novell.com)
6 //  Marek Habersack <mhabersack@novell.com>
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 // 
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 // 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 //
27 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
28 //
29
30
31 using System;
32 using System.Collections;
33 using System.IO;
34 using System.Security;
35 using System.Configuration;
36 using System.Configuration.Internal;
37 using System.Web.Hosting;
38 using System.Web.Util;
39 using System.Reflection;
40
41 /*
42  * this class needs to be rewritten to support usage of the
43  * IRemoteWebConfigurationHostServer interface.  Once that's done, we
44  * need an implementation of that interface that talks (through a web
45  * service?) to a remote site..
46  *
47  * for now, though, just implement it as we do
48  * System.Configuration.InternalConfigurationHost, i.e. the local
49  * case.
50  */
51 namespace System.Web.Configuration
52 {
53         class WebConfigurationHost: IInternalConfigHost
54         {
55                 WebConfigurationFileMap map;
56                 const string MachinePath = ":machine:";
57                 const string MachineWebPath = ":web:";
58
59                 string appVirtualPath;
60                 
61                 public virtual object CreateConfigurationContext (string configPath, string locationSubPath)
62                 {
63                         return new WebContext (WebApplicationLevel.AtApplication /* XXX */,
64                                                "" /* site XXX */,
65                                                "" /* application path XXX */,
66                                                configPath,
67                                                locationSubPath);
68                 }
69                 
70                 public virtual object CreateDeprecatedConfigContext (string configPath)
71                 {
72                         return new HttpConfigurationContext(configPath);
73                 }
74                 
75                 public virtual string DecryptSection (string encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedSection)
76                 {
77                         if (protectedSection == null)
78                                 throw new ArgumentNullException ("protectedSection");
79
80                         return protectedSection.EncryptSection (encryptedXml, protectionProvider);
81                 }
82                 
83                 public virtual void DeleteStream (string streamName)
84                 {
85                         File.Delete (streamName);
86                 }
87                 
88                 public virtual string EncryptSection (string clearXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedSection)
89                 {
90                         if (protectedSection == null)
91                                 throw new ArgumentNullException ("protectedSection");
92
93                         return protectedSection.EncryptSection (clearXml, protectionProvider);
94                 }
95                 
96                 public virtual string GetConfigPathFromLocationSubPath (string configPath, string locationSubPath)
97                 {
98                         if (!String.IsNullOrEmpty (locationSubPath) && !String.IsNullOrEmpty (configPath)) {
99                                 string relConfigPath = configPath.Length == 1 ? null : configPath.Substring (1) + "/";
100                                 if (relConfigPath != null && locationSubPath.StartsWith (relConfigPath, StringComparison.Ordinal))
101                                         locationSubPath = locationSubPath.Substring (relConfigPath.Length);
102                         }
103                         
104                         string ret = configPath + "/" + locationSubPath;
105                         if (!String.IsNullOrEmpty (ret) && ret [0] == '/')
106                                 return ret.Substring (1);
107                         
108                         return ret;
109                 }
110                 
111                 public virtual Type GetConfigType (string typeName, bool throwOnError)
112                 {
113                         Type type = HttpApplication.LoadType (typeName);
114                         if (type == null && throwOnError)
115                                 throw new ConfigurationErrorsException ("Type not found: '" + typeName + "'");
116                         return type;
117                 }
118                 
119                 public virtual string GetConfigTypeName (Type t)
120                 {
121                         return t.AssemblyQualifiedName;
122                 }
123                 
124                 public virtual void GetRestrictedPermissions (IInternalConfigRecord configRecord, out PermissionSet permissionSet,
125                                                               out bool isHostReady)
126                 {
127                         throw new NotImplementedException ();
128                 }
129                 
130                 public virtual string GetStreamName (string configPath)
131                 {
132                         if (configPath == MachinePath) {
133                                 if (map == null)
134                                         return System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile;
135                                 else
136                                         return map.MachineConfigFilename;
137                         } else if (configPath == MachineWebPath) {
138                                 string mdir;
139
140                                 if (map == null)
141                                         mdir = Path.GetDirectoryName (System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile);
142                                 else
143                                         mdir = Path.GetDirectoryName (map.MachineConfigFilename);
144
145                                 return GetWebConfigFileName (mdir);
146                         }
147                         
148                         string dir = MapPath (configPath);
149                         return GetWebConfigFileName (dir);
150                 }
151                 
152                 public virtual string GetStreamNameForConfigSource (string streamName, string configSource)
153                 {
154                         throw new NotImplementedException ();
155                 }
156                 
157                 public virtual object GetStreamVersion (string streamName)
158                 {
159                         throw new NotImplementedException ();
160                 }
161                 
162                 public virtual IDisposable Impersonate ()
163                 {
164                         throw new NotImplementedException ();
165                 }
166                 
167                 public virtual void Init (IInternalConfigRoot root, params object[] hostInitParams)
168                 {
169                 }
170                 
171                 public virtual void InitForConfiguration (ref string locationSubPath, out string configPath,
172                                                           out string locationConfigPath, IInternalConfigRoot root,
173                                                           params object[] hostInitConfigurationParams)
174                 {
175                         string fullPath = (string) hostInitConfigurationParams [1];
176                         map = (WebConfigurationFileMap) hostInitConfigurationParams [0];
177                         bool inAnotherApp = false;
178
179                         if ((hostInitConfigurationParams.Length > 7)
180                                 && (hostInitConfigurationParams[7] is bool))
181                                 inAnotherApp = (bool) hostInitConfigurationParams[7];
182
183                         if (inAnotherApp)
184                                 appVirtualPath = fullPath;
185                         else
186                                 appVirtualPath = HttpRuntime.AppDomainAppVirtualPath;
187                         
188                         if (locationSubPath == MachineWebPath) {
189                                 locationSubPath = MachinePath;
190                                 configPath = MachineWebPath;
191                                 locationConfigPath = null;
192                         } else if (locationSubPath == MachinePath) {
193                                 locationSubPath = null;
194                                 configPath = MachinePath;
195                                 locationConfigPath = null;
196                         } else {
197                                 int i;
198                                 if (locationSubPath == null) {
199                                         configPath = fullPath;
200                                         if (configPath.Length > 1)
201                                                 configPath = VirtualPathUtility.RemoveTrailingSlash (configPath);
202                                 } else
203                                         configPath = locationSubPath;
204                                 
205                                 if (configPath == HttpRuntime.AppDomainAppVirtualPath || configPath == "/")
206                                         i = -1;
207                                 else
208                                         i = configPath.LastIndexOf ("/");
209
210                                 if (i != -1) {
211                                         locationConfigPath = configPath.Substring (i+1);
212                                         
213                                         if (i == 0)
214                                                 locationSubPath = "/";
215                                         else
216                                                 locationSubPath = fullPath.Substring (0, i);
217                                 } else {
218                                         locationSubPath = MachineWebPath;
219                                         locationConfigPath = null;
220                                 }
221                         }
222                 }
223                 
224                 public string MapPath (string virtualPath)
225                 {
226                         if (!String.IsNullOrEmpty (virtualPath)) {
227                                 if (virtualPath.StartsWith (System.Web.Compilation.BuildManager.FAKE_VIRTUAL_PATH_PREFIX, StringComparison.Ordinal))
228                                         return HttpRuntime.AppDomainAppPath;
229                         }
230                         
231                         if (map != null)
232                                 return MapPathFromMapper (virtualPath);
233                         else if (HttpContext.Current != null && HttpContext.Current.Request != null)
234                                 return HttpContext.Current.Request.MapPath (virtualPath);
235                         else if (HttpRuntime.AppDomainAppVirtualPath != null &&
236                                  virtualPath.StartsWith (HttpRuntime.AppDomainAppVirtualPath)) {
237                                 if (virtualPath == HttpRuntime.AppDomainAppVirtualPath)
238                                         return HttpRuntime.AppDomainAppPath;
239                                 return UrlUtils.Combine (HttpRuntime.AppDomainAppPath,
240                                                          virtualPath.Substring (HttpRuntime.AppDomainAppVirtualPath.Length));
241                         }
242                         
243                         return virtualPath;
244                 }
245                 
246                 public string NormalizeVirtualPath (string virtualPath)
247                 {
248                         if (virtualPath == null || virtualPath.Length == 0)
249                                 virtualPath = ".";
250                         else
251                                 virtualPath = virtualPath.Trim ();
252
253                         if (virtualPath [0] == '~' && virtualPath.Length > 2 && virtualPath [1] == '/')
254                                 virtualPath = virtualPath.Substring (1);
255                                 
256                         if (System.IO.Path.DirectorySeparatorChar != '/')
257                                 virtualPath = virtualPath.Replace (System.IO.Path.DirectorySeparatorChar, '/');
258
259                         if (UrlUtils.IsRooted (virtualPath)) {
260                                 virtualPath = UrlUtils.Canonic (virtualPath);
261                         } else {
262                                 if (map.VirtualDirectories.Count > 0) {
263                                         string root = map.VirtualDirectories [0].VirtualDirectory;
264                                         virtualPath = UrlUtils.Combine (root, virtualPath);
265                                         virtualPath = UrlUtils.Canonic (virtualPath);
266                                 }
267                         }
268                         return virtualPath;
269                 }
270
271                 public string MapPathFromMapper (string virtualPath)
272                 {
273                         string path = NormalizeVirtualPath (virtualPath);
274                         
275                         foreach (VirtualDirectoryMapping mapping in map.VirtualDirectories) {
276                                 if (path.StartsWith (mapping.VirtualDirectory)) {
277                                         int i = mapping.VirtualDirectory.Length;
278                                         if (path.Length == i) {
279                                                 return mapping.PhysicalDirectory;
280                                         }
281                                         else if (path [i] == '/') {
282                                                 string pathPart = path.Substring (i + 1).Replace ('/', Path.DirectorySeparatorChar);
283                                                 return Path.Combine (mapping.PhysicalDirectory, pathPart);
284                                         }
285                                 }
286                         }
287                         throw new HttpException ("Invalid virtual directory: " + virtualPath);
288                 }
289
290                 internal static string GetWebConfigFileName (string dir)
291                 {
292                         AppDomain domain = AppDomain.CurrentDomain;
293                         bool hosted = (domain.GetData (ApplicationHost.MonoHostedDataKey) as string) == "yes";
294
295                         if (hosted)
296                                 return ApplicationHost.FindWebConfig (dir);
297                         else {
298                                 Assembly asm = Assembly.GetEntryAssembly () ?? Assembly.GetCallingAssembly ();
299                                 string name = Path.GetFileName (asm.Location);
300                                 string[] fileNames = new string[] {name + ".config", name + ".Config"};
301                                 string appDir = domain.BaseDirectory;
302                                 string file;
303
304                                 foreach (string fn in fileNames) {
305                                         file = Path.Combine (appDir, fn);
306                                         if (File.Exists (file))
307                                                 return file;
308                                 }
309                         }
310                         return null;
311                 }
312                 public virtual bool IsAboveApplication (string configPath)
313                 {
314                         return !configPath.Contains (HttpRuntime.AppDomainAppPath);
315                 }
316                 
317                 public virtual bool IsConfigRecordRequired (string configPath)
318                 {
319                         throw new NotImplementedException ();
320                 }
321                 
322                 public virtual bool IsDefinitionAllowed (string configPath, ConfigurationAllowDefinition allowDefinition,
323                                                          ConfigurationAllowExeDefinition allowExeDefinition)
324                 {
325                         switch (allowDefinition) {
326                                 case ConfigurationAllowDefinition.MachineOnly:
327                                         return configPath == MachinePath || configPath == MachineWebPath;
328                                 case ConfigurationAllowDefinition.MachineToWebRoot:
329                                 case ConfigurationAllowDefinition.MachineToApplication:
330                                         if (String.IsNullOrEmpty (configPath))
331                                                 return true;
332                                         string normalized;
333
334                                         if (VirtualPathUtility.IsRooted (configPath))
335                                                 normalized = VirtualPathUtility.Normalize (configPath);
336                                         else
337                                                 normalized = configPath;
338                                         
339                                         if ((String.Compare (normalized, MachinePath, StringComparison.Ordinal) == 0) ||
340                                                 (String.Compare (normalized, MachineWebPath, StringComparison.Ordinal) == 0))
341                                                         return true;
342                                 
343                                         if ((String.Compare (normalized, appVirtualPath) != 0))
344                                                 return IsApplication (normalized);
345                                 
346                                         return true;
347                                 default:
348                                         return true;
349                         }
350                 }
351                 
352                 [MonoTODO("Should return false in case strPath points to the root of an application.")]
353                 internal bool IsApplication(string strPath)
354                 {
355                         return true;
356                 }
357                 
358                 public virtual bool IsFile (string streamName)
359                 {
360                         throw new NotImplementedException ();
361                 }
362                 
363                 public virtual bool IsLocationApplicable (string configPath)
364                 {
365                         throw new NotImplementedException ();
366                 }
367                 
368                 public virtual Stream OpenStreamForRead (string streamName)
369                 {
370                         if (!File.Exists (streamName)) {
371                                 return null;
372                         }
373                                 
374                         return new FileStream (streamName, FileMode.Open, FileAccess.Read);
375                 }
376
377                 [MonoTODO ("Not implemented")]
378                 public virtual Stream OpenStreamForRead (string streamName, bool assertPermissions)
379                 {
380                         throw new NotImplementedException ();
381                 }
382
383                 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext)
384                 {
385                         if (!IsAboveApplication (streamName))
386                                 WebConfigurationManager.SuppressAppReload (true);
387
388                         return new FileStream (streamName, FileMode.Create, FileAccess.Write);
389                 }
390
391                 [MonoTODO ("Not implemented")]
392                 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext,
393                                                           bool assertPermissions)
394                 {
395                         throw new NotImplementedException ();
396                 }
397                 
398                 public virtual bool PrefetchAll (string configPath, string streamName)
399                 {
400                         throw new NotImplementedException ();
401                 }
402                 
403                 public virtual bool PrefetchSection (string sectionGroupName, string sectionName)
404                 {
405                         throw new NotImplementedException ();
406                 }
407
408                 [MonoTODO ("Not implemented")]
409                 public virtual void RequireCompleteInit (IInternalConfigRecord configRecord)
410                 {
411                         throw new NotImplementedException ();
412                 }
413
414                 public virtual object StartMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
415                 {                       
416                         throw new NotImplementedException ();
417                 }
418                 
419                 public virtual void StopMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
420                 {
421                         throw new NotImplementedException ();
422                 }
423                 
424                 public virtual void VerifyDefinitionAllowed (string configPath, ConfigurationAllowDefinition allowDefinition,
425                                                              ConfigurationAllowExeDefinition allowExeDefinition,
426                                                              IConfigErrorInfo errorInfo)
427                 {
428                         if (!IsDefinitionAllowed (configPath, allowDefinition, allowExeDefinition))
429                                 throw new ConfigurationErrorsException ("The section can't be defined in this file (the allowed definition context is '" + allowDefinition + "').", errorInfo.Filename, errorInfo.LineNumber);
430                 }
431                 
432                 public virtual void WriteCompleted (string streamName, bool success, object writeContext)
433                 {
434                         WriteCompleted (streamName, success, writeContext, false);
435                 }               
436
437                 public virtual void WriteCompleted (string streamName, bool success, object writeContext, bool assertPermissions)
438                 {
439                         // There are probably other things to be done here, but for the moment we
440                         // just mark the completed write as one that should not cause application
441                         // reload. Note that it might already be too late for suppression, since the
442                         // FileSystemWatcher monitor might have already delivered the
443                         // notification. If the stream has been open using OpenStreamForWrite then
444                         // we're safe, though.
445
446                         if (!IsAboveApplication (streamName))
447                                 WebConfigurationManager.SuppressAppReload (true);
448                 }
449
450                 public virtual bool SupportsChangeNotifications {
451                         get { return false; }
452                 }
453                 
454                 public virtual bool SupportsLocation {
455                         get { return false; }
456                 }
457                 
458                 public virtual bool SupportsPath {
459                         get { return false; }
460                 }
461                 
462                 public virtual bool SupportsRefresh {
463                         get { return false; }
464                 }
465
466                 [MonoTODO("Always returns false")]
467                 public virtual bool IsRemote {
468                         get { return false; }
469                 }
470
471                 [MonoTODO ("Not implemented")]
472                 public virtual bool IsFullTrustSectionWithoutAptcaAllowed (IInternalConfigRecord configRecord)
473                 {
474                         throw new NotImplementedException ();
475                 }
476
477                 [MonoTODO ("Not implemented")]
478                 public virtual bool IsInitDelayed (IInternalConfigRecord configRecord)
479                 {
480                         throw new NotImplementedException ();
481                 }
482
483                 [MonoTODO ("Not implemented")]
484                 public virtual bool IsSecondaryRoot (string configPath)
485                 {
486                         throw new NotImplementedException ();
487                 }
488
489                 [MonoTODO ("Not implemented")]
490                 public virtual bool IsTrustedConfigPath (string configPath)
491                 {
492                         throw new NotImplementedException ();
493                 }
494         }
495 }
496