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 CreateConfigurationContext(string configPath, string locationSubPath)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 CreateDeprecatedConfigContext(string configPath)70 public virtual object CreateDeprecatedConfigContext (string configPath) 71 { 72 return new HttpConfigurationContext(configPath); 73 } 74 DecryptSection(string encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedSection)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 DeleteStream(string streamName)83 public virtual void DeleteStream (string streamName) 84 { 85 File.Delete (streamName); 86 } 87 EncryptSection(string clearXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedSection)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 GetConfigPathFromLocationSubPath(string configPath, string locationSubPath)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 GetConfigType(string typeName, bool throwOnError)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 GetConfigTypeName(Type t)119 public virtual string GetConfigTypeName (Type t) 120 { 121 return t.AssemblyQualifiedName; 122 } 123 GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady)124 public virtual void GetRestrictedPermissions (IInternalConfigRecord configRecord, out PermissionSet permissionSet, 125 out bool isHostReady) 126 { 127 throw new NotImplementedException (); 128 } 129 GetStreamName(string configPath)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 GetStreamNameForConfigSource(string streamName, string configSource)152 public virtual string GetStreamNameForConfigSource (string streamName, string configSource) 153 { 154 throw new NotImplementedException (); 155 } 156 GetStreamVersion(string streamName)157 public virtual object GetStreamVersion (string streamName) 158 { 159 throw new NotImplementedException (); 160 } 161 Impersonate()162 public virtual IDisposable Impersonate () 163 { 164 throw new NotImplementedException (); 165 } 166 Init(IInternalConfigRoot root, params object[] hostInitParams)167 public virtual void Init (IInternalConfigRoot root, params object[] hostInitParams) 168 { 169 } 170 InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath, IInternalConfigRoot root, params object[] hostInitConfigurationParams)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 MapPath(string virtualPath)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 NormalizeVirtualPath(string virtualPath)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 MapPathFromMapper(string virtualPath)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 GetWebConfigFileName(string dir)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 } IsAboveApplication(string configPath)312 public virtual bool IsAboveApplication (string configPath) 313 { 314 return !configPath.Contains (HttpRuntime.AppDomainAppPath); 315 } 316 IsConfigRecordRequired(string configPath)317 public virtual bool IsConfigRecordRequired (string configPath) 318 { 319 throw new NotImplementedException (); 320 } 321 IsDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition)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.")] IsApplication(string strPath)353 internal bool IsApplication(string strPath) 354 { 355 return true; 356 } 357 IsFile(string streamName)358 public virtual bool IsFile (string streamName) 359 { 360 throw new NotImplementedException (); 361 } 362 IsLocationApplicable(string configPath)363 public virtual bool IsLocationApplicable (string configPath) 364 { 365 throw new NotImplementedException (); 366 } 367 OpenStreamForRead(string streamName)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")] OpenStreamForRead(string streamName, bool assertPermissions)378 public virtual Stream OpenStreamForRead (string streamName, bool assertPermissions) 379 { 380 throw new NotImplementedException (); 381 } 382 OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext)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")] OpenStreamForWrite(string streamName, string templateStreamName, ref object writeContext, bool assertPermissions)392 public virtual Stream OpenStreamForWrite (string streamName, string templateStreamName, ref object writeContext, 393 bool assertPermissions) 394 { 395 throw new NotImplementedException (); 396 } 397 PrefetchAll(string configPath, string streamName)398 public virtual bool PrefetchAll (string configPath, string streamName) 399 { 400 throw new NotImplementedException (); 401 } 402 PrefetchSection(string sectionGroupName, string sectionName)403 public virtual bool PrefetchSection (string sectionGroupName, string sectionName) 404 { 405 throw new NotImplementedException (); 406 } 407 408 [MonoTODO ("Not implemented")] RequireCompleteInit(IInternalConfigRecord configRecord)409 public virtual void RequireCompleteInit (IInternalConfigRecord configRecord) 410 { 411 throw new NotImplementedException (); 412 } 413 StartMonitoringStreamForChanges(string streamName, StreamChangeCallback callback)414 public virtual object StartMonitoringStreamForChanges (string streamName, StreamChangeCallback callback) 415 { 416 throw new NotImplementedException (); 417 } 418 StopMonitoringStreamForChanges(string streamName, StreamChangeCallback callback)419 public virtual void StopMonitoringStreamForChanges (string streamName, StreamChangeCallback callback) 420 { 421 throw new NotImplementedException (); 422 } 423 VerifyDefinitionAllowed(string configPath, ConfigurationAllowDefinition allowDefinition, ConfigurationAllowExeDefinition allowExeDefinition, IConfigErrorInfo errorInfo)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 WriteCompleted(string streamName, bool success, object writeContext)432 public virtual void WriteCompleted (string streamName, bool success, object writeContext) 433 { 434 WriteCompleted (streamName, success, writeContext, false); 435 } 436 WriteCompleted(string streamName, bool success, object writeContext, bool assertPermissions)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")] IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord)472 public virtual bool IsFullTrustSectionWithoutAptcaAllowed (IInternalConfigRecord configRecord) 473 { 474 throw new NotImplementedException (); 475 } 476 477 [MonoTODO ("Not implemented")] IsInitDelayed(IInternalConfigRecord configRecord)478 public virtual bool IsInitDelayed (IInternalConfigRecord configRecord) 479 { 480 throw new NotImplementedException (); 481 } 482 483 [MonoTODO ("Not implemented")] IsSecondaryRoot(string configPath)484 public virtual bool IsSecondaryRoot (string configPath) 485 { 486 throw new NotImplementedException (); 487 } 488 489 [MonoTODO ("Not implemented")] IsTrustedConfigPath(string configPath)490 public virtual bool IsTrustedConfigPath (string configPath) 491 { 492 throw new NotImplementedException (); 493 } 494 } 495 } 496 497