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
- FormViewDesigner.cs
- XmlSchemas.cs
- ObjectKeyFrameCollection.cs
- RectKeyFrameCollection.cs
- Exceptions.cs
- RevocationPoint.cs
- MimeTypePropertyAttribute.cs
- ListBox.cs
- StylusPointPropertyInfo.cs
- SettingsContext.cs
- MetadataArtifactLoaderCompositeFile.cs
- PnrpPermission.cs
- SettingsAttributeDictionary.cs
- MarkupCompiler.cs
- ReflectionPermission.cs
- QueryStringHandler.cs
- DatagramAdapter.cs
- Math.cs
- UriTemplateLiteralQueryValue.cs
- EncodingNLS.cs
- DataBindingHandlerAttribute.cs
- FileDialog.cs
- ConfigurationManagerHelperFactory.cs
- ToolTip.cs
- XmlNodeChangedEventManager.cs
- WorkerRequest.cs
- StringSource.cs
- DataTablePropertyDescriptor.cs
- TextChange.cs
- BaseTemplateCodeDomTreeGenerator.cs
- EntityKeyElement.cs
- DataRelationCollection.cs
- ScrollChrome.cs
- Expr.cs
- hresults.cs
- BinaryFormatterWriter.cs
- PingOptions.cs
- MouseEvent.cs
- WeakHashtable.cs
- ComUdtElement.cs
- OutputCacheSection.cs
- Viewport2DVisual3D.cs
- StrokeFIndices.cs
- PersonalizablePropertyEntry.cs
- ResourceDescriptionAttribute.cs
- EasingFunctionBase.cs
- ResumeStoryboard.cs
- CompoundFileStorageReference.cs
- XmlStreamNodeWriter.cs
- VarRefManager.cs
- WorkflowIdleBehavior.cs
- OdbcConnectionString.cs
- DPAPIProtectedConfigurationProvider.cs
- PropertyGroupDescription.cs
- CheckBoxAutomationPeer.cs
- ProfileGroupSettingsCollection.cs
- CommandBinding.cs
- SymbolEqualComparer.cs
- Parameter.cs
- UnsignedPublishLicense.cs
- PingReply.cs
- XamlTreeBuilder.cs
- RuleElement.cs
- SortDescription.cs
- AssemblySettingAttributes.cs
- WorkflowDebuggerSteppingAttribute.cs
- StorageTypeMapping.cs
- ViewPort3D.cs
- ParenExpr.cs
- DataGridViewColumnDesignTimeVisibleAttribute.cs
- XmlSchemaSimpleTypeList.cs
- HtmlControlAdapter.cs
- DateTimeUtil.cs
- ValueOfAction.cs
- PropertyPushdownHelper.cs
- TreeViewHitTestInfo.cs
- PersonalizablePropertyEntry.cs
- _SafeNetHandles.cs
- BidirectionalDictionary.cs
- MenuItem.cs
- SchemaComplexType.cs
- LongValidator.cs
- SecurityTokenTypes.cs
- SqlCaseSimplifier.cs
- ProcessInfo.cs
- DescendantQuery.cs
- CellIdBoolean.cs
- ComplexPropertyEntry.cs
- TemplatedMailWebEventProvider.cs
- CodeSubDirectory.cs
- MappedMetaModel.cs
- QueryStringParameter.cs
- AssociationSetEnd.cs
- WorkflowOperationBehavior.cs
- KeyPressEvent.cs
- SwitchCase.cs
- SystemFonts.cs
- SamlConditions.cs
- ManagementObjectCollection.cs
- TdsEnums.cs