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
- WebPartVerb.cs
- DivideByZeroException.cs
- TextEditorCharacters.cs
- ScrollBarRenderer.cs
- base64Transforms.cs
- ConfigurationSectionGroup.cs
- PageParser.cs
- CheckedPointers.cs
- DateTimeOffsetAdapter.cs
- CommonDialog.cs
- XmlObjectSerializerReadContext.cs
- EntityDesignerUtils.cs
- LinqDataSourceSelectEventArgs.cs
- ToolbarAUtomationPeer.cs
- IdentityManager.cs
- XmlDataSourceView.cs
- ScrollChrome.cs
- BaseCodePageEncoding.cs
- LicFileLicenseProvider.cs
- PropertyDescriptorCollection.cs
- ResXBuildProvider.cs
- OleDbMetaDataFactory.cs
- UserNameSecurityTokenProvider.cs
- TextProviderWrapper.cs
- XmlUTF8TextReader.cs
- embossbitmapeffect.cs
- FastPropertyAccessor.cs
- EntityException.cs
- DocumentXPathNavigator.cs
- TCEAdapterGenerator.cs
- MetadataWorkspace.cs
- CancellationToken.cs
- SiteMapNodeItem.cs
- CalendarButtonAutomationPeer.cs
- DataGridHelper.cs
- HttpConfigurationContext.cs
- DataSourceCacheDurationConverter.cs
- JulianCalendar.cs
- HealthMonitoringSectionHelper.cs
- XmlSiteMapProvider.cs
- SQlBooleanStorage.cs
- StringConverter.cs
- ContentDisposition.cs
- UnionExpr.cs
- SchemaElementLookUpTableEnumerator.cs
- XmlSerializerAssemblyAttribute.cs
- ObjectListFieldCollection.cs
- SatelliteContractVersionAttribute.cs
- HttpWriter.cs
- TreeNodeCollection.cs
- TimelineCollection.cs
- DataObjectPastingEventArgs.cs
- CompilationUtil.cs
- PersistenceMetadataNamespace.cs
- PresentationTraceSources.cs
- NativeMethods.cs
- Socket.cs
- OdbcDataAdapter.cs
- Paragraph.cs
- ScriptControlDescriptor.cs
- WsdlBuildProvider.cs
- FactoryGenerator.cs
- StateItem.cs
- KeyInterop.cs
- SelectionChangedEventArgs.cs
- HatchBrush.cs
- ReliableSessionBindingElement.cs
- MsmqIntegrationBindingElement.cs
- EnlistmentTraceIdentifier.cs
- AVElementHelper.cs
- ArgumentReference.cs
- HttpApplication.cs
- EntityClassGenerator.cs
- StrokeCollectionDefaultValueFactory.cs
- ControlBuilder.cs
- EncoderParameters.cs
- MouseEvent.cs
- TableLayout.cs
- ConnectionManagementElement.cs
- PreviewControlDesigner.cs
- NavigationPropertyEmitter.cs
- MdbDataFileEditor.cs
- ArrayMergeHelper.cs
- PropertyGrid.cs
- XhtmlBasicImageAdapter.cs
- Pair.cs
- Track.cs
- CultureInfoConverter.cs
- DynamicContractTypeBuilder.cs
- ProfileSettingsCollection.cs
- ConvertEvent.cs
- Rotation3DAnimation.cs
- Stack.cs
- SpeechDetectedEventArgs.cs
- cookie.cs
- XpsPackagingPolicy.cs
- SHA384.cs
- ZipPackagePart.cs
- IssuanceLicense.cs
- UnsafeNativeMethods.cs