Code:
/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / fx / src / xsp / System / Web / CachedPathData.cs / 6 / 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; // 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 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). // // 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; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- NavigateUrlConverter.cs
- UnitySerializationHolder.cs
- OdbcParameterCollection.cs
- ObjectViewFactory.cs
- ImageMetadata.cs
- DrawingContextDrawingContextWalker.cs
- VectorKeyFrameCollection.cs
- AddressHeaderCollectionElement.cs
- DefinitionUpdate.cs
- SymbolTable.cs
- Int32AnimationBase.cs
- PathSegment.cs
- Route.cs
- CommunicationException.cs
- XmlReaderSettings.cs
- FtpCachePolicyElement.cs
- IRCollection.cs
- InputScopeAttribute.cs
- SystemEvents.cs
- ProbeDuplex11AsyncResult.cs
- SSmlParser.cs
- DriveNotFoundException.cs
- FileDialogCustomPlacesCollection.cs
- ControlTemplate.cs
- StaticFileHandler.cs
- BinaryObjectWriter.cs
- TransactionManager.cs
- Accessors.cs
- InternalBufferOverflowException.cs
- SourceInterpreter.cs
- XmlSerializerSection.cs
- X509ThumbprintKeyIdentifierClause.cs
- IfJoinedCondition.cs
- KeyValuePairs.cs
- ProvidersHelper.cs
- ValidatedControlConverter.cs
- Location.cs
- LicFileLicenseProvider.cs
- SpeechSeg.cs
- VisualCollection.cs
- ProcessModelInfo.cs
- Parameter.cs
- NativeCppClassAttribute.cs
- ArrayHelper.cs
- SurrogateEncoder.cs
- StringKeyFrameCollection.cs
- PageHandlerFactory.cs
- TableStyle.cs
- CancelEventArgs.cs
- IsolatedStorageFile.cs
- HttpCachePolicy.cs
- BrowserCapabilitiesCompiler.cs
- ClickablePoint.cs
- PropertyMap.cs
- EntityKeyElement.cs
- MonthChangedEventArgs.cs
- PasswordBox.cs
- DesignerSerializationOptionsAttribute.cs
- TabRenderer.cs
- TextCollapsingProperties.cs
- RootDesignerSerializerAttribute.cs
- CoreSwitches.cs
- StylusPointDescription.cs
- StyleXamlTreeBuilder.cs
- XsdBuildProvider.cs
- WpfWebRequestHelper.cs
- TextTrailingWordEllipsis.cs
- LinqDataSource.cs
- SQLBinaryStorage.cs
- XmlCollation.cs
- Clock.cs
- TypefaceMetricsCache.cs
- EditCommandColumn.cs
- MimePart.cs
- EDesignUtil.cs
- DeferredReference.cs
- DocumentViewerBase.cs
- storepermission.cs
- PropertyPathConverter.cs
- SettingsContext.cs
- MailMessageEventArgs.cs
- ConnectionInterfaceCollection.cs
- BinaryCommonClasses.cs
- Quaternion.cs
- DataSetMappper.cs
- SmiGettersStream.cs
- TypeConverterAttribute.cs
- Accessible.cs
- TextViewSelectionProcessor.cs
- HotSpot.cs
- QueryableDataSourceEditData.cs
- XmlAttributeCollection.cs
- TabControlCancelEvent.cs
- _NegotiateClient.cs
- TextTreeTextBlock.cs
- HtmlImage.cs
- ToolStripItem.cs
- BufferManager.cs
- TypeName.cs
- XmlObjectSerializerReadContextComplexJson.cs