Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / CachedPathData.cs / 4 / CachedPathData.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Web { using System.Collections; using System.Configuration; using System.Configuration.Internal; using System.Globalization; using System.Security.Principal; using System.Threading; using System.Web.Security; using System.Web.SessionState; using System.Web.Configuration; using System.Web.Caching; using System.Web.Hosting; using System.Web.Util; using System.Web.UI; using System.Security.Permissions; // Data about a path that is cached across requests class CachedPathData { internal const int FInited = 0x0001; internal const int FCompletedFirstRequest = 0x0002; internal const int FExists = 0x0004; internal const int FOwnsConfigRecord = 0x0010; // is this the highest ancestor pointing to the config record? internal const int FClosed = 0x0020; // Has item been closed already? internal const int FCloseNeeded = 0x0040; // Should we close? static CacheItemRemovedCallback s_callback = new CacheItemRemovedCallback(CachedPathData.OnCacheItemRemoved); #pragma warning disable 0649 SafeBitVector32 _flags; #pragma warning restore 0649 string _configPath; VirtualPath _virtualPath; string _physicalPath; RuntimeConfig _runtimeConfig; HandlerMappingMemo _handlerMemo; // // Constructor // internal CachedPathData(string configPath, VirtualPath virtualPath, string physicalPath, bool exists) { // Guarantee that we return a non-null config record // if an error occurs during initialization. _runtimeConfig = RuntimeConfig.GetErrorRuntimeConfig(); _configPath = configPath; _virtualPath = virtualPath; _physicalPath = physicalPath; _flags[FExists] = exists; // VSWhidbey 607683: Config loading for web app has a dependency on CachedPathData. // On the other hand, Config also has a dependency on Uri class which has // a new static constructor that calls config, and eventually to CachedPathData again. // We need a dummy reference to Uri class so the static constructor would be involved // first to initialize config. string dummy = System.Uri.SchemeDelimiter; } // // Get CachedPathData for the machine.config level // static internal CachedPathData GetMachinePathData() { return GetConfigPathData(WebConfigurationHost.MachineConfigPath); } // // Get CachedPathData for the root web.config path // static internal CachedPathData GetRootWebPathData() { return GetConfigPathData(WebConfigurationHost.RootWebConfigPath); } // // Get CachedPathData for the application. // static internal CachedPathData GetApplicationPathData() { if (!HostingEnvironment.IsHosted) { return GetRootWebPathData(); } return GetConfigPathData(HostingEnvironment.AppConfigPath); } // // Get CachedPathData for a virtual path. // The path may be supplied by user code, so check that it is valid. // static internal CachedPathData GetVirtualPathData(VirtualPath virtualPath, bool permitPathsOutsideApp) { if (!HostingEnvironment.IsHosted) { return GetRootWebPathData(); } // Make sure it's not relative if (virtualPath != null) { virtualPath.FailIfRelativePath(); } // Check if the path is within the application. if (virtualPath == null || !virtualPath.IsWithinAppRoot) { if (permitPathsOutsideApp) { return GetApplicationPathData(); } else { throw new ArgumentException(SR.GetString( SR.Cross_app_not_allowed, (virtualPath != null) ? virtualPath.VirtualPathString : "null")); } } // Construct a configPath based on the unvalidated virtualPath. string configPath = WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(HostingEnvironment.SiteID, virtualPath); // Pass the virtualPath to GetConfigPathData to validate in the case where the // CachedPathData for the unsafeConfigPath is not found. return GetConfigPathData(configPath); } // Example of configPath = "machine/webroot/1/fxtest/sub/foo.aspx" // The configPath parameter must be lower case. static private CachedPathData GetConfigPathData(string configPath) { Debug.Assert(ConfigPathUtility.IsValid(configPath), "ConfigPathUtility.IsValid(configPath)"); Debug.Assert(configPath == configPath.ToLower(CultureInfo.InvariantCulture), "configPath == configPath.ToLower(CultureInfo.InvariantCulture)"); // // First, see if the CachedPathData is in the cache. // we don't use Add for this lookup, as doing so requires // creating a CacheDependency, which can be slow as it may hit // the filesystem. // string key = CreateKey(configPath); CacheInternal cacheInternal = HttpRuntime.CacheInternal; CachedPathData data = (CachedPathData) cacheInternal.Get(key); // if found, return the data if (data != null) { data.WaitForInit(); return data; } // if not found, try to add it CachedPathData parentData = null; CacheDependency dependency = null; VirtualPath virtualPath = null; string physicalPath = null; bool exists = false; string[] fileDependencies = null; string[] cacheItemDependencies = null; string siteID = null; // WOS bool cacheEntryIsNotRemovable = false; if (WebConfigurationHost.IsMachineConfigPath(configPath)) { exists = true; cacheEntryIsNotRemovable = true; } else { // Make sure we have the parent data so we can create a dependency on the parent. // The parent dependency will ensure that configuration data in the parent // will be referenced by a cache hit on the child. (see UtcUpdateUsageRecursive in Cache.cs) string parentConfigPath = ConfigPathUtility.GetParent(configPath); parentData = GetConfigPathData(parentConfigPath); string parentKey = CreateKey(parentConfigPath); cacheItemDependencies = new string[1] {parentKey}; if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath)) { // assume hardcoded levels above the path, such as root web.config, exist exists = true; cacheEntryIsNotRemovable = true; } else { // Ensure that the physical path does not look suspicious (MSRC 5556). WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out virtualPath); try { physicalPath = virtualPath.MapPathInternal(true); } catch (HttpException e) { // // Treat exceptions that are thrown because the path is suspicious // as "404 Not Found" exceptions. Implementations of MapPath // will throw HttpException with no error code if the path is // suspicious. // if (e.GetHttpCode() == 500) { throw new HttpException(404, String.Empty); } else { throw; } } // // Throw "404 Not Found" if the path is suspicious and // the implementation of MapPath has not already done so. // FileUtil.CheckSuspiciousPhysicalPath(physicalPath); // Add a dependency on the path itself, if it is a file, // to handle the case where a file is deleted and replaced // with a directory of the same name. bool isDirectory = false; if (String.IsNullOrEmpty(physicalPath)) { exists = false; } else { FileUtil.PhysicalPathStatus(physicalPath, false, false, out exists, out isDirectory); } if (exists && !isDirectory) { fileDependencies = new string[1] {physicalPath}; } } try { dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies); } catch { // CacheDependency ctor could fail because of bogus file path // and it is ok not to watch those } } // Try to add the CachedPathData to the cache. CachedPathData dataAdd = null; bool isDataCreator = false; bool initCompleted = false; CacheItemPriority priority = cacheEntryIsNotRemovable ? CacheItemPriority.NotRemovable : CacheItemPriority.Normal; try { using (dependency) { dataAdd = new CachedPathData(configPath, virtualPath, physicalPath, exists); try { } finally { data = (CachedPathData) cacheInternal.UtcAdd(key, dataAdd, dependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, priority, s_callback); if (data == null) { isDataCreator = true; } } } // If another thread added it first, return the data if (!isDataCreator) { data.WaitForInit(); return data; } // This thread is the creator of the CachedPathData, initialize it lock (dataAdd) { try { dataAdd.Init(parentData); initCompleted = true; } finally { // free waiters dataAdd._flags[FInited] = true; // Wake up waiters. Monitor.PulseAll(dataAdd); if (dataAdd._flags[FCloseNeeded]) { // If we have received a call back to close, then lets // make sure that our config object is cleaned up dataAdd.Close(); } } } } finally { // All the work in this finally block is for the case where we're the // creator of the CachedPathData. if (isDataCreator) { // if (!dataAdd._flags[FInited]) { lock (dataAdd) { // free waiters dataAdd._flags[FInited] = true; // Wake up waiters. Monitor.PulseAll(dataAdd); if (dataAdd._flags[FCloseNeeded]) { // If we have received a call back to close, then lets // make sure that our config object is cleaned up dataAdd.Close(); } } } // // Even though there is a try/catch handler surrounding the call to Init, // a ThreadAbortException can still cause the handler to be bypassed. // // If there is an error, either a thread abort or an error in the config // file itself, we do want to leave the item cached for a short period // so that we do not revisit the error and potentially reparse the config file // on every request. // // The reason we simply do not leave the item in the cache forever is that the // problem that caused the configuration exception may be fixed without touching // the config file in a way that causes a file change notification (for example, an // acl change in a parent directory, or a change of path mapping in the metabase). // // NOTE: It is important to reinsert the item into the cache AFTER dropping // the lock on dataAdd, in order to prevent the possibility of deadlock. // Debug.Assert(dataAdd._flags[FInited], "_flags[FInited]"); if (!initCompleted || (dataAdd.ConfigRecord != null && dataAdd.ConfigRecord.HasInitErrors)) { // // Create a new dependency object as the old one cannot be reused. // Do not include a file dependency if initialization could not be completed, // as invoking the file system could lead to further errors during a thread abort. // if (dependency != null) { if (!initCompleted) { dependency = new CacheDependency(0, null, cacheItemDependencies); } else { dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies); } } using (dependency) { cacheInternal.UtcInsert(key, dataAdd, dependency, DateTime.UtcNow.AddSeconds(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_callback); } } } } return dataAdd; } // Remove CachedPathData when the first request for the path results in a // 400 range error. We need to remove all data up the path to account for // virtual files. // An example of a 400 range error is "path not found". static internal void RemoveBadPathData(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; string key = CreateKey(configPath); while (pathData != null && !pathData.CompletedFirstRequest && !pathData.Exists) { cacheInternal.Remove(key); configPath = ConfigPathUtility.GetParent(configPath); if (configPath == null) break; key = CreateKey(configPath); pathData = (CachedPathData) cacheInternal.Get(key); } } // Mark CachedPathData as completed when the first request for the path results in a // status outside the 400 range. We need to mark all data up the path to account for // virtual files. static internal void MarkCompleted(CachedPathData pathData) { CacheInternal cacheInternal = HttpRuntime.CacheInternal; string configPath = pathData._configPath; do { pathData.CompletedFirstRequest = true; configPath = ConfigPathUtility.GetParent(configPath); if (configPath == null) break; string key = CreateKey(configPath); pathData = (CachedPathData) cacheInternal.Get(key); } while (pathData != null && !pathData.CompletedFirstRequest); } // Close // // Close the object. This does not mean it can not be used anymore, // it just means that the cleanup as been done, so we don't have // to worry about closing it anymore // void Close() { // Only close if we are propertly initialized if (_flags[FInited]) { // Only close if we haven't already closed if (_flags.ChangeValue(FClosed, true)) { // Remove the config record if we own it // N.B. ConfigRecord.Remove is safe to call more than once. if (_flags[FOwnsConfigRecord]) { ConfigRecord.Remove(); } } } } // OnCacheItemRemoved // // Notification the items has been removed from the cache. Flag // the item to be cleaned up, and then try cleanup // static void OnCacheItemRemoved(string key, object value, CacheItemRemovedReason reason) { CachedPathData data = (CachedPathData) value; data._flags[FCloseNeeded] = true; data.Close(); } static string CreateKey(string configPath) { Debug.Assert(configPath == configPath.ToLower(CultureInfo.InvariantCulture), "configPath == configPath.ToLower(CultureInfo.InvariantCulture)"); return CacheInternal.PrefixPathData + configPath; } // Initialize the data void Init(CachedPathData parentData) { // Note that _runtimeConfig will be set to the singleton instance of ErrorRuntimeConfig // if a ThreadAbortException is thrown during this method. Debug.Assert(_runtimeConfig == RuntimeConfig.GetErrorRuntimeConfig(), "_runtimeConfig == RuntimeConfig.GetErrorRuntimeConfig()"); if (!HttpConfigurationSystem.UseHttpConfigurationSystem) { // // configRecord may legitimately be null if we are not using the HttpConfigurationSystem. // _runtimeConfig = null; } else { IInternalConfigRecord configRecord = HttpConfigurationSystem.GetUniqueConfigRecord(_configPath); Debug.Assert(configRecord != null, "configRecord != null"); if (configRecord.ConfigPath.Length == _configPath.Length) { // // The config is unique to this path, so this make this record the owner of the config. // _flags[FOwnsConfigRecord] = true; _runtimeConfig = new RuntimeConfig(configRecord); } else { // // The config record is the same as an ancestor's, so use the parent's RuntimeConfig. // Debug.Assert(parentData != null, "parentData != null"); _runtimeConfig = parentData._runtimeConfig; } } } void WaitForInit() { // Wait for the data to be initialized. if (!_flags[FInited]) { lock (this) { if (!_flags[FInited]) { Monitor.Wait(this); } } } } internal bool CompletedFirstRequest { get {return _flags[FCompletedFirstRequest];} set { _flags[FCompletedFirstRequest] = value; } } internal VirtualPath Path { get {return _virtualPath;} } internal string PhysicalPath { get {return _physicalPath;} } internal bool Exists { get {return _flags[FExists];} } internal HandlerMappingMemo CachedHandler { get {return _handlerMemo;} set {_handlerMemo = value;} } internal IInternalConfigRecord ConfigRecord { get { // _runtimeConfig may be null if we are not using the HttpConfigurationSystem. return (_runtimeConfig != null) ? _runtimeConfig.ConfigRecord : null; } } internal RuntimeConfig RuntimeConfig { get { return _runtimeConfig; } } } }
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PointAnimation.cs
- HTMLTextWriter.cs
- Util.cs
- PhonemeEventArgs.cs
- Visitor.cs
- cache.cs
- RepeatInfo.cs
- RadioButtonAutomationPeer.cs
- IconHelper.cs
- WebReferencesBuildProvider.cs
- FunctionGenerator.cs
- PostBackOptions.cs
- DataGridViewMethods.cs
- ListViewCommandEventArgs.cs
- GridViewRowCollection.cs
- SerializationStore.cs
- SoapDocumentServiceAttribute.cs
- EventPrivateKey.cs
- DeviceContext.cs
- DataServiceResponse.cs
- TriggerActionCollection.cs
- SqlComparer.cs
- SafeNativeMethods.cs
- TreeViewEvent.cs
- CultureNotFoundException.cs
- SimpleBitVector32.cs
- SafeNativeMethods.cs
- UniqueIdentifierService.cs
- MarkupObject.cs
- HttpRequest.cs
- DataContext.cs
- SettingsAttributeDictionary.cs
- ZeroOpNode.cs
- NCryptSafeHandles.cs
- DesignDataSource.cs
- WebSysDefaultValueAttribute.cs
- WorkflowElementDialogWindow.xaml.cs
- BindingOperations.cs
- MethodCallTranslator.cs
- HierarchicalDataBoundControl.cs
- FormClosingEvent.cs
- NameNode.cs
- MetricEntry.cs
- ExpressionBindings.cs
- DefaultPropertyAttribute.cs
- PieceNameHelper.cs
- XmlSchemaDatatype.cs
- ClientScriptManager.cs
- DtcInterfaces.cs
- XmlQueryTypeFactory.cs
- _NestedSingleAsyncResult.cs
- ListInitExpression.cs
- TemplateInstanceAttribute.cs
- WebPartPersonalization.cs
- ActivityScheduledRecord.cs
- UpdateTracker.cs
- CRYPTPROTECT_PROMPTSTRUCT.cs
- SqlDataSourceAdvancedOptionsForm.cs
- IconConverter.cs
- UiaCoreTypesApi.cs
- Transform3D.cs
- Parser.cs
- TraceHandlerErrorFormatter.cs
- ServiceDescriptionReflector.cs
- MessageQueueConverter.cs
- SystemIPInterfaceProperties.cs
- PointCollectionConverter.cs
- OdbcUtils.cs
- PartitionResolver.cs
- FontWeights.cs
- Rotation3D.cs
- SessionEndingCancelEventArgs.cs
- CodeDomConfigurationHandler.cs
- ExtenderProvidedPropertyAttribute.cs
- StyleCollectionEditor.cs
- BinaryObjectInfo.cs
- OpenFileDialog.cs
- ColorTransform.cs
- BitmapEffect.cs
- FileFormatException.cs
- COM2IDispatchConverter.cs
- DistinctQueryOperator.cs
- Zone.cs
- AttachedAnnotationChangedEventArgs.cs
- prefixendpointaddressmessagefiltertable.cs
- BitStack.cs
- VersionValidator.cs
- ExpressionPrinter.cs
- WorkflowMarkupSerializerMapping.cs
- PageOutputQuality.cs
- TypeInfo.cs
- CodeMemberEvent.cs
- PackWebRequestFactory.cs
- HuffModule.cs
- _Connection.cs
- DataList.cs
- SoapAttributeOverrides.cs
- RegistryConfigurationProvider.cs
- sqlstateclientmanager.cs
- EmptyStringExpandableObjectConverter.cs