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 = (bool) hostInitConfigurationParams [7];
180 appVirtualPath = fullPath;
182 appVirtualPath = HttpRuntime.AppDomainAppVirtualPath;
184 if (locationSubPath == MachineWebPath) {
185 locationSubPath = MachinePath;
186 configPath = MachineWebPath;
187 locationConfigPath = null;
188 } else if (locationSubPath == MachinePath) {
189 locationSubPath = null;
190 configPath = MachinePath;
191 locationConfigPath = null;
194 if (locationSubPath == null) {
195 configPath = fullPath;
196 if (configPath.Length > 1)
197 configPath = VirtualPathUtility.RemoveTrailingSlash (configPath);
199 configPath = locationSubPath;
201 if (configPath == HttpRuntime.AppDomainAppVirtualPath || configPath == "/")
204 i = configPath.LastIndexOf ("/");
207 locationConfigPath = configPath.Substring (i+1);
210 locationSubPath = "/";
212 locationSubPath = fullPath.Substring (0, i);
214 locationSubPath = MachineWebPath;
215 locationConfigPath = null;
220 public string MapPath (string virtualPath)
222 if (!String.IsNullOrEmpty (virtualPath)) {
223 if (virtualPath.StartsWith (System.Web.Compilation.BuildManager.FAKE_VIRTUAL_PATH_PREFIX, StringComparison.Ordinal))
224 return HttpRuntime.AppDomainAppPath;
228 return MapPathFromMapper (virtualPath);
229 else if (HttpContext.Current != null && HttpContext.Current.Request != null)
230 return HttpContext.Current.Request.MapPath (virtualPath);
231 else if (HttpRuntime.AppDomainAppVirtualPath != null &&
232 virtualPath.StartsWith (HttpRuntime.AppDomainAppVirtualPath)) {
233 if (virtualPath == HttpRuntime.AppDomainAppVirtualPath)
234 return HttpRuntime.AppDomainAppPath;
235 return UrlUtils.Combine (HttpRuntime.AppDomainAppPath,
236 virtualPath.Substring (HttpRuntime.AppDomainAppVirtualPath.Length));
242 public string NormalizeVirtualPath (string virtualPath)
244 if (virtualPath == null || virtualPath.Length == 0)
247 virtualPath = virtualPath.Trim ();
249 if (virtualPath [0] == '~' && virtualPath.Length > 2 && virtualPath [1] == '/')
250 virtualPath = virtualPath.Substring (1);
252 if (System.IO.Path.DirectorySeparatorChar != '/')
253 virtualPath = virtualPath.Replace (System.IO.Path.DirectorySeparatorChar, '/');
255 if (UrlUtils.IsRooted (virtualPath)) {
256 virtualPath = UrlUtils.Canonic (virtualPath);
258 if (map.VirtualDirectories.Count > 0) {
259 string root = map.VirtualDirectories [0].VirtualDirectory;
260 virtualPath = UrlUtils.Combine (root, virtualPath);
261 virtualPath = UrlUtils.Canonic (virtualPath);
267 public string MapPathFromMapper (string virtualPath)
269 string path = NormalizeVirtualPath (virtualPath);
271 foreach (VirtualDirectoryMapping mapping in map.VirtualDirectories) {
272 if (path.StartsWith (mapping.VirtualDirectory)) {
273 int i = mapping.VirtualDirectory.Length;
274 if (path.Length == i) {
275 return mapping.PhysicalDirectory;
277 else if (path [i] == '/') {
278 string pathPart = path.Substring (i + 1).Replace ('/', Path.DirectorySeparatorChar);
279 return Path.Combine (mapping.PhysicalDirectory, pathPart);
283 throw new HttpException ("Invalid virtual directory: " + virtualPath);
286 internal static string GetWebConfigFileName (string dir)
288 AppDomain domain = AppDomain.CurrentDomain;
289 bool hosted = (domain.GetData (ApplicationHost.MonoHostedDataKey) as string) == "yes";
292 return ApplicationHost.FindWebConfig (dir);
294 Assembly asm = Assembly.GetEntryAssembly () ?? Assembly.GetCallingAssembly ();
295 string name = Path.GetFileName (asm.Location);
296 string[] fileNames = new string[] {name + ".config", name + ".Config"};
297 string appDir = domain.BaseDirectory;
300 foreach (string fn in fileNames) {
301 file = Path.Combine (appDir, fn);
302 if (File.Exists (file))
308 public virtual bool IsAboveApplication (string configPath)
310 return !configPath.Contains (HttpRuntime.AppDomainAppPath);
313 public virtual bool IsConfigRecordRequired (string configPath)
315 throw new NotImplementedException ();
318 public virtual bool IsDefinitionAllowed (string configPath, ConfigurationAllowDefinition allowDefinition,
319 ConfigurationAllowExeDefinition allowExeDefinition)
321 switch (allowDefinition) {
322 case ConfigurationAllowDefinition.MachineOnly:
323 return configPath == MachinePath || configPath == MachineWebPath;
324 case ConfigurationAllowDefinition.MachineToWebRoot:
325 case ConfigurationAllowDefinition.MachineToApplication:
326 if (String.IsNullOrEmpty (configPath))
330 if (VirtualPathUtility.IsRooted (configPath))
331 normalized = VirtualPathUtility.Normalize (configPath);
333 normalized = configPath;
335 if ((String.Compare (normalized, MachinePath, StringComparison.Ordinal) == 0) ||
336 (String.Compare (normalized, MachineWebPath, StringComparison.Ordinal) == 0))
339 if ((String.Compare (normalized, appVirtualPath) != 0))
340 return IsApplication (normalized);
348 [MonoTODO("Should return false in case strPath points to the root of an application.")]
349 internal bool IsApplication(string strPath)
354 public virtual bool IsFile (string streamName)
356 throw new NotImplementedException ();
359 public virtual bool IsLocationApplicable (string configPath)
361 throw new NotImplementedException ();
364 public virtual Stream OpenStreamForRead (string streamName)
366 if (!File.Exists (streamName)) {
370 return new FileStream (streamName, FileMode.Open, FileAccess.Read);
373 [MonoTODO ("Not implemented")]
374 public virtual Stream OpenStreamForRead (string streamName, bool assertPermissions)
376 throw new NotImplementedException ();
379 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext)
381 if (!IsAboveApplication (streamName))
382 WebConfigurationManager.SuppressAppReload (true);
384 return new FileStream (streamName, FileMode.Create, FileAccess.Write);
387 [MonoTODO ("Not implemented")]
388 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext,
389 bool assertPermissions)
391 throw new NotImplementedException ();
394 public virtual bool PrefetchAll (string configPath, string streamName)
396 throw new NotImplementedException ();
399 public virtual bool PrefetchSection (string sectionGroupName, string sectionName)
401 throw new NotImplementedException ();
404 [MonoTODO ("Not implemented")]
405 public virtual void RequireCompleteInit (IInternalConfigRecord configRecord)
407 throw new NotImplementedException ();
410 public virtual object StartMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
412 throw new NotImplementedException ();
415 public virtual void StopMonitoringStreamForChanges (string streamName, StreamChangeCallback callback)
417 throw new NotImplementedException ();
420 public virtual void VerifyDefinitionAllowed (string configPath, ConfigurationAllowDefinition allowDefinition,
421 ConfigurationAllowExeDefinition allowExeDefinition,
422 IConfigErrorInfo errorInfo)
424 if (!IsDefinitionAllowed (configPath, allowDefinition, allowExeDefinition))
425 throw new ConfigurationErrorsException ("The section can't be defined in this file (the allowed definition context is '" + allowDefinition + "').", errorInfo.Filename, errorInfo.LineNumber);
428 public virtual void WriteCompleted (string streamName, bool success, object writeContext)
430 WriteCompleted (streamName, success, writeContext, false);
433 public virtual void WriteCompleted (string streamName, bool success, object writeContext, bool assertPermissions)
435 // There are probably other things to be done here, but for the moment we
436 // just mark the completed write as one that should not cause application
437 // reload. Note that it might already be too late for suppression, since the
438 // FileSystemWatcher monitor might have already delivered the
439 // notification. If the stream has been open using OpenStreamForWrite then
440 // we're safe, though.
442 if (!IsAboveApplication (streamName))
443 WebConfigurationManager.SuppressAppReload (true);
446 public virtual bool SupportsChangeNotifications {
447 get { return false; }
450 public virtual bool SupportsLocation {
451 get { return false; }
454 public virtual bool SupportsPath {
455 get { return false; }
458 public virtual bool SupportsRefresh {
459 get { return false; }
462 [MonoTODO("Always returns false")]
463 public virtual bool IsRemote {
464 get { return false; }
467 [MonoTODO ("Not implemented")]
468 public virtual bool IsFullTrustSectionWithoutAptcaAllowed (IInternalConfigRecord configRecord)
470 throw new NotImplementedException ();
473 [MonoTODO ("Not implemented")]
474 public virtual bool IsInitDelayed (IInternalConfigRecord configRecord)
476 throw new NotImplementedException ();
479 [MonoTODO ("Not implemented")]
480 public virtual bool IsSecondaryRoot (string configPath)
482 throw new NotImplementedException ();
485 [MonoTODO ("Not implemented")]
486 public virtual bool IsTrustedConfigPath (string configPath)
488 throw new NotImplementedException ();