2 // System.Web.Configuration.WebConfigurationHost.cs
5 // Lluis Sanchez Gual (lluis@novell.com)
6 // Marek Habersack <mhabersack@novell.com>
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:
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
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.
27 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
32 using System.Collections;
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;
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..
47 * for now, though, just implement it as we do
48 * System.Configuration.InternalConfigurationHost, i.e. the local
51 namespace System.Web.Configuration
53 class WebConfigurationHost: IInternalConfigHost
55 WebConfigurationFileMap map;
56 const string MachinePath = ":machine:";
57 const string MachineWebPath = ":web:";
59 string appVirtualPath;
61 public virtual object CreateConfigurationContext (string configPath, string locationSubPath)
63 return new WebContext (WebApplicationLevel.AtApplication /* XXX */,
65 "" /* application path XXX */,
70 public virtual object CreateDeprecatedConfigContext (string configPath)
72 return new HttpConfigurationContext(configPath);
75 public virtual string DecryptSection (string encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedSection)
77 if (protectedSection == null)
78 throw new ArgumentNullException ("protectedSection");
80 return protectedSection.EncryptSection (encryptedXml, protectionProvider);
83 public virtual void DeleteStream (string streamName)
85 File.Delete (streamName);
88 public virtual string EncryptSection (string clearXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedSection)
90 if (protectedSection == null)
91 throw new ArgumentNullException ("protectedSection");
93 return protectedSection.EncryptSection (clearXml, protectionProvider);
96 public virtual string GetConfigPathFromLocationSubPath (string configPath, string locationSubPath)
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);
104 string ret = configPath + "/" + locationSubPath;
105 if (!String.IsNullOrEmpty (ret) && ret [0] == '/')
106 return ret.Substring (1);
111 public virtual Type GetConfigType (string typeName, bool throwOnError)
113 Type type = HttpApplication.LoadType (typeName);
114 if (type == null && throwOnError)
115 throw new ConfigurationErrorsException ("Type not found: '" + typeName + "'");
119 public virtual string GetConfigTypeName (Type t)
121 return t.AssemblyQualifiedName;
124 public virtual void GetRestrictedPermissions (IInternalConfigRecord configRecord, out PermissionSet permissionSet,
125 out bool isHostReady)
127 throw new NotImplementedException ();
130 public virtual string GetStreamName (string configPath)
132 if (configPath == MachinePath) {
134 return System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile;
136 return map.MachineConfigFilename;
137 } else if (configPath == MachineWebPath) {
141 mdir = Path.GetDirectoryName (System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile);
143 mdir = Path.GetDirectoryName (map.MachineConfigFilename);
145 return GetWebConfigFileName (mdir);
148 string dir = MapPath (configPath);
149 return GetWebConfigFileName (dir);
152 public virtual string GetStreamNameForConfigSource (string streamName, string configSource)
154 throw new NotImplementedException ();
157 public virtual object GetStreamVersion (string streamName)
159 throw new NotImplementedException ();
162 public virtual IDisposable Impersonate ()
164 throw new NotImplementedException ();
167 public virtual void Init (IInternalConfigRoot root, params object[] hostInitParams)
171 public virtual void InitForConfiguration (ref string locationSubPath, out string configPath,
172 out string locationConfigPath, IInternalConfigRoot root,
173 params object[] hostInitConfigurationParams)
175 string fullPath = (string) hostInitConfigurationParams [1];
176 map = (WebConfigurationFileMap) hostInitConfigurationParams [0];
177 bool inAnotherApp = false;
179 if ((hostInitConfigurationParams.Length > 7)
180 && (hostInitConfigurationParams[7] is bool))
181 inAnotherApp = (bool) hostInitConfigurationParams[7];
184 appVirtualPath = fullPath;
186 appVirtualPath = HttpRuntime.AppDomainAppVirtualPath;
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;
198 if (locationSubPath == null) {
199 configPath = fullPath;
200 if (configPath.Length > 1)
201 configPath = VirtualPathUtility.RemoveTrailingSlash (configPath);
203 configPath = locationSubPath;
205 if (configPath == HttpRuntime.AppDomainAppVirtualPath || configPath == "/")
208 i = configPath.LastIndexOf ("/");
211 locationConfigPath = configPath.Substring (i+1);
214 locationSubPath = "/";
216 locationSubPath = fullPath.Substring (0, i);
218 locationSubPath = MachineWebPath;
219 locationConfigPath = null;
224 public string MapPath (string virtualPath)
226 if (!String.IsNullOrEmpty (virtualPath)) {
227 if (virtualPath.StartsWith (System.Web.Compilation.BuildManager.FAKE_VIRTUAL_PATH_PREFIX, StringComparison.Ordinal))
228 return HttpRuntime.AppDomainAppPath;
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));
246 public string NormalizeVirtualPath (string virtualPath)
248 if (virtualPath == null || virtualPath.Length == 0)
251 virtualPath = virtualPath.Trim ();
253 if (virtualPath [0] == '~' && virtualPath.Length > 2 && virtualPath [1] == '/')
254 virtualPath = virtualPath.Substring (1);
256 if (System.IO.Path.DirectorySeparatorChar != '/')
257 virtualPath = virtualPath.Replace (System.IO.Path.DirectorySeparatorChar, '/');
259 if (UrlUtils.IsRooted (virtualPath)) {
260 virtualPath = UrlUtils.Canonic (virtualPath);
262 if (map.VirtualDirectories.Count > 0) {
263 string root = map.VirtualDirectories [0].VirtualDirectory;
264 virtualPath = UrlUtils.Combine (root, virtualPath);
265 virtualPath = UrlUtils.Canonic (virtualPath);
271 public string MapPathFromMapper (string virtualPath)
273 string path = NormalizeVirtualPath (virtualPath);
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;
281 else if (path [i] == '/') {
282 string pathPart = path.Substring (i + 1).Replace ('/', Path.DirectorySeparatorChar);
283 return Path.Combine (mapping.PhysicalDirectory, pathPart);
287 throw new HttpException ("Invalid virtual directory: " + virtualPath);
290 internal static string GetWebConfigFileName (string dir)
292 AppDomain domain = AppDomain.CurrentDomain;
293 bool hosted = (domain.GetData (ApplicationHost.MonoHostedDataKey) as string) == "yes";
296 return ApplicationHost.FindWebConfig (dir);
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;
304 foreach (string fn in fileNames) {
305 file = Path.Combine (appDir, fn);
306 if (File.Exists (file))
312 public virtual bool IsAboveApplication (string configPath)
314 return !configPath.Contains (HttpRuntime.AppDomainAppPath);
317 public virtual bool IsConfigRecordRequired (string configPath)
319 throw new NotImplementedException ();
322 public virtual bool IsDefinitionAllowed (string configPath, ConfigurationAllowDefinition allowDefinition,
323 ConfigurationAllowExeDefinition allowExeDefinition)
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))
334 if (VirtualPathUtility.IsRooted (configPath))
335 normalized = VirtualPathUtility.Normalize (configPath);
337 normalized = configPath;
339 if ((String.Compare (normalized, MachinePath, StringComparison.Ordinal) == 0) ||
340 (String.Compare (normalized, MachineWebPath, StringComparison.Ordinal) == 0))
343 if ((String.Compare (normalized, appVirtualPath) != 0))
344 return IsApplication (normalized);
352 [MonoTODO("Should return false in case strPath points to the root of an application.")]
353 internal bool IsApplication(string strPath)
358 public virtual bool IsFile (string streamName)
360 throw new NotImplementedException ();
363 public virtual bool IsLocationApplicable (string configPath)
365 throw new NotImplementedException ();
368 public virtual Stream OpenStreamForRead (string streamName)
370 if (!File.Exists (streamName)) {
374 return new FileStream (streamName, FileMode.Open, FileAccess.Read);
377 [MonoTODO ("Not implemented")]
378 public virtual Stream OpenStreamForRead (string streamName, bool assertPermissions)
380 throw new NotImplementedException ();
383 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext)
385 if (!IsAboveApplication (streamName))
386 WebConfigurationManager.SuppressAppReload (true);
388 return new FileStream (streamName, FileMode.Create, FileAccess.Write);
391 [MonoTODO ("Not implemented")]
392 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext,
393 bool assertPermissions)
395 throw new NotImplementedException ();
398 public virtual bool PrefetchAll (string configPath, string streamName)
400 throw new NotImplementedException ();
403 public virtual bool PrefetchSection (string sectionGroupName, string sectionName)
405 throw new NotImplementedException ();
408 [MonoTODO ("Not implemented")]
409 public virtual void RequireCompleteInit (IInternalConfigRecord configRecord)
411 throw new NotImplementedException ();
414 public virtual object StartMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
416 throw new NotImplementedException ();
419 public virtual void StopMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
421 throw new NotImplementedException ();
424 public virtual void VerifyDefinitionAllowed (string configPath, ConfigurationAllowDefinition allowDefinition,
425 ConfigurationAllowExeDefinition allowExeDefinition,
426 IConfigErrorInfo errorInfo)
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);
432 public virtual void WriteCompleted (string streamName, bool success, object writeContext)
434 WriteCompleted (streamName, success, writeContext, false);
437 public virtual void WriteCompleted (string streamName, bool success, object writeContext, bool assertPermissions)
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.
446 if (!IsAboveApplication (streamName))
447 WebConfigurationManager.SuppressAppReload (true);
450 public virtual bool SupportsChangeNotifications {
451 get { return false; }
454 public virtual bool SupportsLocation {
455 get { return false; }
458 public virtual bool SupportsPath {
459 get { return false; }
462 public virtual bool SupportsRefresh {
463 get { return false; }
466 [MonoTODO("Always returns false")]
467 public virtual bool IsRemote {
468 get { return false; }
471 [MonoTODO ("Not implemented")]
472 public virtual bool IsFullTrustSectionWithoutAptcaAllowed (IInternalConfigRecord configRecord)
474 throw new NotImplementedException ();
477 [MonoTODO ("Not implemented")]
478 public virtual bool IsInitDelayed (IInternalConfigRecord configRecord)
480 throw new NotImplementedException ();
483 [MonoTODO ("Not implemented")]
484 public virtual bool IsSecondaryRoot (string configPath)
486 throw new NotImplementedException ();
489 [MonoTODO ("Not implemented")]
490 public virtual bool IsTrustedConfigPath (string configPath)
492 throw new NotImplementedException ();