Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / ServiceHostingEnvironment.cs / 3 / ServiceHostingEnvironment.cs
//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------------------- namespace System.ServiceModel { using System.Configuration; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Net; using System.Runtime.CompilerServices; using System.ServiceModel.Activation; using System.ServiceModel.Channels; using System.ServiceModel.Diagnostics; using System.ServiceModel.ComIntegration; using System.Threading; using System.Web; using System.Web.Compilation; using System.Web.Configuration; using System.Web.Hosting; using System.Runtime.Serialization; using System.Security.Principal; using System.ServiceModel.Configuration; using System.Runtime; using System.Runtime.InteropServices; using System.ComponentModel; using System.Security.Permissions; using System.Security; public static class ServiceHostingEnvironment { static object syncRoot = new object(); static HostingManager hostingManager; static bool isHosted; static bool isSimpleApplicationHost; static Int64 requestCount; static bool didAssemblyCheck; static bool isApplicationDomainHosted; internal const string VerbPost = "POST"; internal const string ISAPIApplicationIdPrefix = "/LM/W3SVC/"; internal const string RelativeVirtualPathPrefix = "~"; internal const string ServiceParserDelimiter = "|"; const char FileExtensionSeparator = '.'; const char UriSchemeSeparator = ':'; const char PathSeparator = '/'; ////// Critical - Calls into an unsafe UnsafeLogEvent method /// TreatAsSafe - Event identities cannot be spoofed as they are constants determined inside the method /// [SecurityCritical, SecurityTreatAsSafe] static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { if (DiagnosticUtility.ShouldTraceError) { Exception exception = e.ExceptionObject as Exception; DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostUnhandledException, true, DiagnosticTrace.CreateSourceString(sender), exception == null ? string.Empty : exception.ToString()); } } ////// Review - called by ProcessRequest outside of the restricted SecurityContext /// [SecurityRequiresReview] public static bool AspNetCompatibilityEnabled { ////// Review - can be called outside of user context. /// [SecurityRequiresReview] get { if (!IsHosted) return false; return IsAspNetCompatibilityEnabled(); } } ////// Review - called by ServiceHostFactory.CreateServiceHost /// [SecurityRequiresReview] internal static Uri[] PrefixFilters { [SecurityRequiresReview] get { if (!IsHosted) return null; return GetBaseAddressPrefixFilters(); } } ////// Review - can be called outside of user context. /// [SecurityRequiresReview] [MethodImpl(MethodImplOptions.NoInlining)] static bool IsAspNetCompatibilityEnabled() { return hostingManager.AspNetCompatibilityEnabled; } ////// Review - can be called outside of user context. /// [SecurityRequiresReview] [MethodImpl(MethodImplOptions.NoInlining)] static Uri[] GetBaseAddressPrefixFilters() { return hostingManager.BaseAddressPrefixFilters; } public static void EnsureServiceAvailable(string virtualPath) { if (string.IsNullOrEmpty(virtualPath)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("virtualPath")); if (virtualPath.IndexOf(UriSchemeSeparator) > 0) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.Hosting_AddressIsAbsoluteUri, virtualPath), "virtualPath")); EnsureInitialized(); virtualPath = NormalizeVirtualPath(virtualPath); EnsureServiceAvailableFast(virtualPath); } internal static void EnsureServiceAvailableFast(string relativeVirtualPath) { try { hostingManager.EnsureServiceAvailable(relativeVirtualPath); } catch (ServiceActivationException exception) { LogServiceActivationException(exception); throw; } } ////// Critical - Calls into an unsafe UnsafeLogEvent method /// TreatAsSafe - Event identities cannot be spoofed as they are constants determined inside the method /// [SecurityCritical, SecurityTreatAsSafe] private static void LogServiceActivationException(ServiceActivationException exception) { if (exception.InnerException is HttpException) { string messageAsString = SafeTryGetHtmlErrorMessage((HttpException)exception.InnerException); if (messageAsString == null || messageAsString.Length == 0) messageAsString = exception.Message; DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostHttpError, true, DiagnosticTrace.CreateSourceString(hostingManager), messageAsString, exception == null ? string.Empty : exception.ToString()); } else { DiagnosticUtility.UnsafeEventLog.UnsafeLogEvent(TraceEventType.Error, EventLogCategory.WebHost, EventLogEventId.WebHostFailedToProcessRequest, true, DiagnosticTrace.CreateSourceString(hostingManager), exception == null ? string.Empty : exception.ToString()); } } static bool canGetHtmlErrorMessage = true; static string SafeTryGetHtmlErrorMessage(HttpException exception) { if (exception != null && canGetHtmlErrorMessage) { try { return exception.GetHtmlErrorMessage(); } catch (SecurityException e) { canGetHtmlErrorMessage = false; // not re-throwing on purpose if (DiagnosticUtility.ShouldTraceWarning) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning); } } } return null; } ////// Review - can be called outside of user context. /// [SecurityRequiresReview] internal static void IncrementRequestCount() { Interlocked.Increment(ref requestCount); } internal static void DecrementRequestCount() { Interlocked.Decrement(ref requestCount); Debug.Assert(requestCount >= 0, "Request count should always be non-nagative."); if (requestCount == 0) { if (hostingManager != null) { hostingManager.NotifyAllRequestDone(); } } } internal static string CurrentVirtualPath { get { DiagnosticUtility.DebugAssert(IsHosted, "CurrentVirtualPath should not be called from non web-hosted environment."); return hostingManager.CurrentVirtualPath; } } internal static void ProcessNotMatchedEndpointAddress(Uri uri, string endpointName) { if (ServiceHostingEnvironment.AspNetCompatibilityEnabled && !object.ReferenceEquals(uri.Scheme, Uri.UriSchemeHttp) && !object.ReferenceEquals(uri.Scheme, Uri.UriSchemeHttps)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_NonHTTPInCompatibilityMode, endpointName))); } } ////// Review - called by ProcessRequest outside of the restricted SecurityContext /// [SecurityRequiresReview] internal static bool GetExtensionSupported(string extension) { DiagnosticUtility.DebugAssert(IsHosted, "GetExtensionSupported should not be called from non web-hosted environment."); return hostingManager.GetExtensionSupported(extension); } internal static bool IsRecycling { get { DiagnosticUtility.DebugAssert(IsHosted, "IsRecycling should not be called from non web-hosted environment."); return hostingManager.IsRecycling; } } static object ThisLock { get { return syncRoot; } } internal static void DecrementBusyCount() { if (ServiceHostingEnvironment.IsHosted) HostingEnvironmentWrapper.DecrementBusyCount(); } internal static void IncrementBusyCount() { if (ServiceHostingEnvironment.IsHosted) HostingEnvironmentWrapper.IncrementBusyCount(); } ////// Review - called by ProcessRequest outside of the restricted SecurityContext /// [SecurityRequiresReview] internal static void SafeEnsureInitialized() { if (hostingManager == null) { PartialTrustHelpers.PartialTrustInvoke(new ContextCallback(OnEnsureInitialized), null); } } static void OnEnsureInitialized(object state) { EnsureInitialized(); } internal static void EnsureInitialized() { if (hostingManager != null) return; lock (ThisLock) { if (hostingManager != null) return; if (!HostingEnvironmentWrapper.IsHosted) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_ProcessNotExecutingUnderHostedContext, "ServiceHostingEnvironment.EnsureServiceAvailable"))); HostingManager tempHostingManager = new HostingManager(); // register the following code when we use the service environment class // the first time // HookADUnhandledExceptionEvent(); Thread.MemoryBarrier(); isSimpleApplicationHost = GetIsSimpleApplicationHost(); hostingManager = tempHostingManager; isHosted = true; } } ////// Critical - Satisfies a LinkDemand for SecurityPermission(ControlAppDomain) on HookADUnhandledExceptionEvent /// Safe - no control flow in for handler /// [SecurityCritical, SecurityTreatAsSafe] static void HookADUnhandledExceptionEvent() { AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; } ////// Critical - Uses SecurityCritical property UnsafeApplicationID to get application id with an elevation /// Safe - processes result into a simple bool which is not protected /// [SecurityCritical, SecurityTreatAsSafe] static bool GetIsSimpleApplicationHost() { // ASPNET won't provide API to check Cassini. But it's safe and performant to check only // the ApplicationID prefix (MessageBus Bug 24832). return (string.Compare(ISAPIApplicationIdPrefix, 0, HostingEnvironmentWrapper.UnsafeApplicationID, 0, ISAPIApplicationIdPrefix.Length, StringComparison.OrdinalIgnoreCase) != 0); } internal static string NormalizeVirtualPath(string virtualPath) { string processedVirtualPath = null; try { // Convert the virtual path to relative if not already is. processedVirtualPath = VirtualPathUtility.ToAppRelative(virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath); } catch (HttpException exception) { // We want to throw an ArgumentException. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(exception.Message, "virtualPath", exception)); } if (string.IsNullOrEmpty(processedVirtualPath) || !processedVirtualPath.StartsWith(RelativeVirtualPathPrefix, StringComparison.Ordinal)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.Hosting_AddressPointsOutsideTheVirtualDirectory, virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath))); } // Find the position to start. int pos = processedVirtualPath.IndexOf(FileExtensionSeparator); while (pos > 0) { // Search inside the processedVirtualPath to find the extension. pos = processedVirtualPath.IndexOf(PathSeparator, pos + 1); string subVirtualPath = (pos == -1) ? processedVirtualPath : processedVirtualPath.Substring(0, pos); string extension = VirtualPathUtility.GetExtension(subVirtualPath); if ((!string.IsNullOrEmpty(extension)) && ServiceHostingEnvironment.GetExtensionSupported(extension)) { // Remove the pathinfo. return subVirtualPath; } } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.Hosting_ServiceNotExist, virtualPath))); } internal static bool IsHosted { ////// Review - can be called outside of user context. /// [SecurityRequiresReview] get { return isHosted; } } internal static bool IsSimpleApplicationHost { get { DiagnosticUtility.DebugAssert(IsHosted, "IsSimpleApplicationHost should not be called from non web-hosted environment."); return isSimpleApplicationHost; } } const string SystemWebComma = "System.Web,"; internal static bool ApplicationDomainHosted { get { if (didAssemblyCheck) { return isApplicationDomainHosted; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (string.Compare(assemblies[i].FullName, 0, SystemWebComma, 0, SystemWebComma.Length, StringComparison.OrdinalIgnoreCase) == 0) { isApplicationDomainHosted = IsApplicationDomainHosted(); break; } } didAssemblyCheck = true; return isApplicationDomainHosted; } } ////// Critical - Assert a demand for AspNetHostingPermission /// Safe - Only queries if we are hosted - no actual action is initiated, no critical /// information is leaking. /// [MethodImpl(MethodImplOptions.NoInlining)] [SecurityCritical, SecurityTreatAsSafe] [AspNetHostingPermission(SecurityAction.Assert, Level = AspNetHostingPermissionLevel.Minimal)] static bool IsApplicationDomainHosted() { return HostingEnvironment.IsHosted; } class HostingManager : IRegisteredObject { IDictionarydirectory; readonly ExtensionHelper extensions; bool aspNetCompatibilityEnabled; bool isUnregistered; bool isRecycling; bool isStopStarted; static object syncRoot = new object(); Uri[] baseAddressPrefixFilters; // One instance per appdomain, don't need to be disposed. ManualResetEvent allRequestDoneInStop = new ManualResetEvent(false); /// /// Critical - Admin-provided value that allows for machine resource allocation /// [SecurityCritical] int minFreeMemoryPercentageToActivateService; [ThreadStatic] string currentVirtualPath; internal HostingManager() { this.directory = new Dictionary(16, StringComparer.OrdinalIgnoreCase); try { RegisterObject(); LoadConfigParameters(); this.extensions = new ExtensionHelper(); } finally { // Make sure failure to construct is idempotent if (this.extensions == null) { UnregisterObject(); } } } /// /// Critical - Uses SecurityCritical method UnsafeGetSection to get config with an elevation /// - Sets minFreeMemoryPercentageToActivateService /// Safe - does not leak config objects /// [SecurityCritical, SecurityTreatAsSafe] private void LoadConfigParameters() { ServiceHostingEnvironmentSection section = ServiceHostingEnvironmentSection.UnsafeGetSection(); this.aspNetCompatibilityEnabled = section.AspNetCompatibilityEnabled; this.minFreeMemoryPercentageToActivateService = section.MinFreeMemoryPercentageToActivateService; ListprefixFilters = new List (); foreach (BaseAddressPrefixFilterElement element in section.BaseAddressPrefixFilters) { prefixFilters.Add(element.Prefix); } this.baseAddressPrefixFilters = prefixFilters.ToArray(); } /// /// Review - can be called outside of user context. /// [SecurityRequiresReview] internal bool GetExtensionSupported(string extension) { return extensions.GetExtensionSupported(extension); } internal bool AspNetCompatibilityEnabled { ////// Review - can be called outside of user context. /// [SecurityRequiresReview] get { return aspNetCompatibilityEnabled; } } internal Uri[] BaseAddressPrefixFilters { ////// Review - can be called outside of user context. /// [SecurityRequiresReview] get { return baseAddressPrefixFilters; } } internal string CurrentVirtualPath { get { return currentVirtualPath; } } internal static object ThisLock { get { return syncRoot; } } internal bool IsRecycling { get { return isRecycling; } } internal void EnsureServiceAvailable(string normalizedVirtualPath) { TryDebugPrint("HostingManager.EnsureServiceAvailable(" + normalizedVirtualPath + ")"); ServiceActivationInfo activationInfo = null; // 1. Use global lock to find ServiceActivationInfo lock (ThisLock) { if (directory.TryGetValue(normalizedVirtualPath, out activationInfo)) { if (activationInfo.Service != null) return; } FailActivationIfRecyling(normalizedVirtualPath); if (activationInfo == null) { // Check service file existence. if (!HostingEnvironment.VirtualPathProvider.FileExists(normalizedVirtualPath)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new EndpointNotFoundException( SR.GetString( SR.Hosting_ServiceNotExist, VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)))); } activationInfo = new ServiceActivationInfo(normalizedVirtualPath); directory.Add(normalizedVirtualPath, activationInfo); } } // 2. Use local lock to activate the service. ServiceHostBase newService = null; lock (activationInfo) { if (activationInfo.Service != null) { // The service has been activated by another thread. return; } FailActivationIfRecyling(normalizedVirtualPath); try { CheckMemoryGates(); newService = ActivateService(normalizedVirtualPath); // We need to lock and check IsRecycling here because it could race with Abort method. lock (ThisLock) { if (!IsRecycling) { activationInfo.Service = newService; } } if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent( TraceEventType.Information, TraceCode.WebHostServiceActivated, new StringTraceRecord("VirtualPath", VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)), this, (Exception)null); } } catch (HttpCompileException ex) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ServiceActivationException(SR.GetString(SR.Hosting_ServiceCannotBeActivated, VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath), ex.Message), ex)); } catch (ServiceActivationException) { throw; } #pragma warning suppress 56500 // covered by FxCOP catch (Exception ex) { // If it is a fatal exception, don't wrap it. if (DiagnosticUtility.IsFatal(ex)) { throw; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ServiceActivationException(SR.GetString(SR.Hosting_ServiceCannotBeActivated, VirtualPathUtility.ToAbsolute(normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath), ex.Message), ex)); } finally { currentVirtualPath = null; } } if (activationInfo.Service == null) { DiagnosticUtility.DebugAssert( IsRecycling && (newService != null), "Must happen in recycling state, also new service must has been created."); newService.Abort(); } FailActivationIfRecyling(normalizedVirtualPath); } ////// Critical - Accesses minFreeMemoryPercentageToActivateService, calls Check /// Safe - no input / output, safe operation if called with administrator-provided value /// [SecurityCritical, SecurityTreatAsSafe] void CheckMemoryGates() { ServiceMemoryGates.Check(this.minFreeMemoryPercentageToActivateService); } ServiceHostBase ActivateService(string normalizedVirtualPath) { ServiceHostBase service = CreateService(normalizedVirtualPath); service.Closed += this.OnServiceClosed; FailActivationIfRecyling(normalizedVirtualPath); try { service.Open(); } finally { if (service.State != CommunicationState.Opened) { // Abort the service to clear possible cached information. service.Abort(); } } return service; } ////// Critical - Uses SecurityCritical method UnsafeImpersonate to establish the impersonation context /// Safe - does not leak anything, does not let caller influence impersonation /// // Why this triple try blocks instead of using "using" statement: // 1. "using" will do the impersonation prior to entering the try, // which leaves an opertunity to Thread.Abort this thread and get it to exit the method still impersonated. // 2. put the assignment of unsafeImpersonate in a finally block // in order to prevent Threat.Abort after impersonation but before the assignment. // 3. the finally of a "using" doesn't run until exception filters higher up the stack have executed. // they will do so in the impersonated context if an exception is thrown inside the try. // In sumary, this should prevent the thread from existing this method well still impersonated. [SecurityCritical, SecurityTreatAsSafe] string GetCompiledCustomString(string normalizedVirtualPath) { try { IDisposable unsafeImpersonate = null; try { try { } finally { unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate(); } return BuildManager.GetCompiledCustomString(normalizedVirtualPath); } finally { if (null != unsafeImpersonate) { unsafeImpersonate.Dispose(); } } } catch { throw; } } static Uri[] FilterBaseAddressList(Uri[] baseAddresses, Uri[] prefixFilters) { // Precondition assumption: // filterAddresses only contains one Uri per scheme. // Enforced by throwing exception when duplicates found. Listresults = new List (); Dictionary schemeMappings = new Dictionary (); foreach (Uri filterUri in prefixFilters) { if (!schemeMappings.ContainsKey(filterUri.Scheme)) { schemeMappings.Add(filterUri.Scheme, filterUri); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BaseAddressDuplicateScheme, filterUri.Scheme))); } } foreach (Uri baseUri in baseAddresses) { string scheme = baseUri.Scheme; if (schemeMappings.ContainsKey(scheme)) { Uri filterUri = schemeMappings[scheme]; if ((baseUri.Port == filterUri.Port) && (string.Compare(baseUri.Host, filterUri.Host, StringComparison.OrdinalIgnoreCase) == 0)) { results.Add(baseUri); } } else { results.Add(baseUri); } } return results.ToArray(); } ServiceHostBase CreateService(string normalizedVirtualPath) { // 1. Compile the service // The expected format is: // | | // The first two cannot be empty. string compiledString = GetCompiledCustomString(normalizedVirtualPath); if (string.IsNullOrEmpty(compiledString)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_CompilationResultEmpty, normalizedVirtualPath))); } TryDebugPrint("HostingManager.CreateService() BuildManager.GetCompiledCustomString() returned compiledString: " + compiledString); string[] compiledStrings = compiledString.Split(ServiceParserDelimiter.ToCharArray()); if (compiledStrings.Length < 3) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_CompilationResultInvalid, normalizedVirtualPath))); } // 2. Add the base addresses Uri[] baseAddresses = HostedTransportConfigurationManager.GetBaseAddresses(compiledStrings[0]); Uri[] prefixFilters = ServiceHostingEnvironment.PrefixFilters; if (prefixFilters != null && prefixFilters.Length > 0) { baseAddresses = FilterBaseAddressList(baseAddresses, prefixFilters); } // We generate the virtual path from compiled string so that it will has correct case. normalizedVirtualPath = VirtualPathUtility.ToAppRelative(compiledStrings[0], HostingEnvironmentWrapper.ApplicationVirtualPath); // Get the current virtual path (full path except for the .svc file name). currentVirtualPath = compiledStrings[0].Substring(0, compiledStrings[0].LastIndexOf('/')); if (currentVirtualPath.Length == 0) { currentVirtualPath = "/"; } // 3. Create service ServiceHostBase service = null; ServiceHostFactoryBase factory = null; if (string.IsNullOrEmpty(compiledStrings[1])) factory = new ServiceHostFactory(); else { Type compiledType = Type.GetType(compiledStrings[1]); if (!typeof(ServiceHostFactoryBase).IsAssignableFrom(compiledType)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_IServiceHostNotImplemented, compiledStrings[1]))); ConstructorInfo ctor = compiledType.GetConstructor(new Type[] { }); if (ctor == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_NoDefaultCtor, compiledStrings[1]))); factory = (ServiceHostFactoryBase)ctor.Invoke(new object[] { }); } // Push assembly context into ServiceHostFactory if (factory is ServiceHostFactory) { for (int index = 3; index < compiledStrings.Length; ++index) ((ServiceHostFactory)factory).AddAssemblyReference(compiledStrings[index]); } service = factory.CreateServiceHost(compiledStrings[2], baseAddresses); if (service == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.Hosting_ServiceHostBaseIsNull, compiledStrings[2]))); } // 4. Create VirtualPathExtension for ServiceHostBase VirtualPathExtension virtualPathExtension = new VirtualPathExtension(normalizedVirtualPath); service.Extensions.Add(virtualPathExtension); return service; } void FailActivationIfRecyling(string normalizedVirtualPath) { if (IsRecycling) { InvalidOperationException exception = new InvalidOperationException(SR.GetString( SR.Hosting_EnvironmentShuttingDown, normalizedVirtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ServiceActivationException(exception.Message, exception)); } } public void Stop(bool immediate) { if (!immediate) { // Try to wait for all requests to be done, then close all the ServiceHosts. IOThreadScheduler.ScheduleCallback(new WaitCallback(WaitAndCloseCallback), this); } else { // Will execute here only if HostingEnvironment.UnregisterObject hasn't been called. Abort(); } } static bool canDebugPrint = true; [Conditional("DEBUG")] static void TryDebugPrint(string message) { if (canDebugPrint) { try { Debug.Print(message); } catch (SecurityException e) { canDebugPrint = false; // not re-throwing on purpose if (DiagnosticUtility.ShouldTraceWarning) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning); } } } } void OnServiceClosed(object sender, EventArgs e) { lock (ThisLock) { if (!isRecycling) { ServiceHostBase closedService = (ServiceHostBase)sender; string key = null; foreach (string address in directory.Keys) { if (directory[address].Service == closedService) { key = address; break; } } if (key != null) { directory.Remove(key); } } } } internal void NotifyAllRequestDone() { if (isStopStarted) { allRequestDoneInStop.Set(); } } void Abort() { allRequestDoneInStop.Set(); List > list = null; lock (ThisLock) { // We need to set isRecycling inside lock because we want to make sure no // new request will be handed once we start to shut down. isRecycling = true; if (UnregisterObject()) { return; } // Make a copy of directory. list = new List >(directory); } // Enumerate all the ServiceHosts, abort them one by one. for (int i = 0; i < list.Count; i++) { //If it is called with immediate=true, then we will abort all the services. if (list[i].Value.Service != null) { try { list[i].Value.Service.Abort(); } catch (Exception exception) { if (!(DiagnosticUtility.IsFatal(exception))) { LogServiceCloseError(list[i].Key, exception); } throw; } } RemoveCachedService(list[i].Key); } } void WaitAndCloseCallback(object obj) { isStopStarted = true; if (ServiceHostingEnvironment.requestCount != 0) { allRequestDoneInStop.WaitOne(); } List > list = null; lock (ThisLock) { if (UnregisterObject()) { return; } // Make a copy of directory. list = new List >(directory); } // Enumerate all the ServiceHosts, close them one by one. AsyncCallback callback = null; for (int i = 0; i < list.Count; i++) { if (list[i].Value.Service != null) { // We will try to close all the services asynchronously. if (callback == null) { callback = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnCloseService)); } IAsyncResult result = null; try { // Set timeout to MaxValue and so that only ASP.NET setting is used. result = list[i].Value.Service.BeginClose(TimeSpan.MaxValue, callback, list[i]); } catch (Exception exception) { // If BeginClose throw an exception, abort should already have been called. if (!(DiagnosticUtility.IsFatal(exception))) { LogServiceCloseError(list[i].Key, exception); } if (!(exception is CommunicationException)) { throw; } // We will remove the service and continue processing other services // if a CommunicationException happened. RemoveCachedService(list[i].Key); } if (result != null && result.CompletedSynchronously) { EndCloseService(result); } } else { RemoveCachedService(list[i].Key); } } } void OnCloseService(IAsyncResult result) { if (!result.CompletedSynchronously) { EndCloseService(result); } } void EndCloseService(IAsyncResult result) { KeyValuePair item = (KeyValuePair )result.AsyncState; try { item.Value.Service.EndClose(result); } catch (Exception exception) { //If EndClose throw an exception, abort should already have been called. if (DiagnosticUtility.IsFatal(exception)) { throw; } LogServiceCloseError(item.Key, exception); } RemoveCachedService(item.Key); } void RemoveCachedService(string path) { lock (ThisLock) { // At the time when we just removed all the service, we will unregister // from HostingEnvironement. directory.Remove(path); UnregisterObject(); } } void LogServiceCloseError(string virtualPath, Exception exception) { if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.WebHostServiceCloseFailed, new StringTraceRecord("VirtualPath", VirtualPathUtility.ToAbsolute(virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath)), this, exception); } } /// /// Critical - Uses HostingEnvironmentWrapper.UnsafeRegisterObject which is critical /// Safe - doesn't allow the caller to control the variable -- only registers 'this' /// [SecurityCritical, SecurityTreatAsSafe] void RegisterObject() { HostingEnvironmentWrapper.UnsafeRegisterObject(this); } // Note : this method should only be called under lock of ThisLock. ////// Critical - Uses HostingEnvironmentWrapper.UnsafeUnregisterObject which is critical /// Safe - doesn't allow the caller to control the variable -- only unregisters 'this' /// [SecurityCritical, SecurityTreatAsSafe] bool UnregisterObject() { if (directory.Count == 0) { if (!isUnregistered) { isUnregistered = true; HostingEnvironmentWrapper.UnsafeUnregisterObject(this); } return true; } return false; } class ExtensionHelper { readonly IDictionarybuildProviders; /// /// Critical - loads config through an elevation and stores results /// Safe - stores results in BuildProviderInfo instances which restrict access to the BuildProvider config object /// [SecurityCritical, SecurityTreatAsSafe] public ExtensionHelper() { buildProviders = new Dictionary(8, StringComparer.OrdinalIgnoreCase); CompilationSection compilationSection = (CompilationSection)ConfigurationHelpers.UnsafeGetSectionFromWebConfigurationManager("system.web/compilation"); foreach (System.Web.Configuration.BuildProvider buildProvider in compilationSection.BuildProviders) { buildProviders.Add(buildProvider.Extension, new BuildProviderInfo(buildProvider)); } } /// /// Review - can be called outside of user context. /// [SecurityRequiresReview] public bool GetExtensionSupported(string extension) { BuildProviderInfo info; if (!buildProviders.TryGetValue(extension, out info)) return false; return info.IsSupported; } } } class ServiceActivationInfo { string virtualPath; ServiceHostBase service; public ServiceActivationInfo(string virtualPath) { this.virtualPath = virtualPath; } public ServiceHostBase Service { get { return this.service; } set { this.service = value; } } } class BuildProviderInfo { ////// Critical - stores the result of an elevation /// [SecurityCritical] System.Web.Configuration.BuildProvider buildProvider; bool initialized; bool isSupported; object thisLock = new object(); ////// Critical - stores the result of an elevation /// Safe - stores it in a Critical field /// [SecurityCritical, SecurityTreatAsSafe] public BuildProviderInfo(System.Web.Configuration.BuildProvider buildProvider) { this.buildProvider = buildProvider; } ////// Review - can be called outside of user context. /// [SecurityRequiresReview] void EnsureInitialized() { if (initialized) return; lock (thisLock) { if (initialized) return; Type type = Type.GetType(BuildProviderType, false); if (type == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { type = assemblies[i].GetType(BuildProviderType, false); if (type != null) break; } } if (type != null) { object[] attributes = System.ServiceModel.Description.ServiceReflector.GetCustomAttributes(type, typeof(ServiceActivationBuildProviderAttribute), true); if (attributes.Length > 0) { isSupported = true; } } ClearBuildProvider(); initialized = true; } } string BuildProviderType { ////// Critical - accesses the SecurityCritical buildProvider field /// Safe - returns the Type property, which is allowed; doesn't leak the BuildProvider instance /// [SecurityCritical, SecurityTreatAsSafe] get { return buildProvider.Type; } } ////// Review - can be called outside of user context. /// [SecurityRequiresReview] public bool IsSupported { get { EnsureInitialized(); return isSupported; } } ////// Critical - accesses the SecurityCritical buildProvider field /// - Can be called outside user context. /// Safe - just clears it, doesn't leak anything /// [SecurityCritical, SecurityTreatAsSafe] void ClearBuildProvider() { this.buildProvider = null; } } } } // 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
- MailSettingsSection.cs
- DateTimeUtil.cs
- SchemaImporter.cs
- ExpressionBuilder.cs
- basemetadatamappingvisitor.cs
- UpdatePanelTriggerCollection.cs
- ChildrenQuery.cs
- WebPartTransformer.cs
- HyperLinkColumn.cs
- MetaModel.cs
- TextServicesDisplayAttribute.cs
- TagNameToTypeMapper.cs
- X509WindowsSecurityToken.cs
- ValidationEventArgs.cs
- DocumentManager.cs
- TypeLibConverter.cs
- XamlTypeMapper.cs
- ContainsRowNumberChecker.cs
- BasePattern.cs
- externdll.cs
- CompilerGlobalScopeAttribute.cs
- LogicalMethodInfo.cs
- StructuredType.cs
- XPathNodeIterator.cs
- IdnMapping.cs
- FilterQueryOptionExpression.cs
- SqlConnectionPoolGroupProviderInfo.cs
- EventOpcode.cs
- LockRecursionException.cs
- ValueTable.cs
- TextFormatterImp.cs
- DesignerDataTable.cs
- PageTrueTypeFont.cs
- AnnotationResourceCollection.cs
- ExpressionServices.cs
- HwndStylusInputProvider.cs
- IRCollection.cs
- BindingFormattingDialog.cs
- XPathPatternParser.cs
- WindowsScrollBar.cs
- SerialPort.cs
- UnitySerializationHolder.cs
- DbDataReader.cs
- BooleanAnimationBase.cs
- WindowsListViewSubItem.cs
- InternalControlCollection.cs
- COM2ExtendedUITypeEditor.cs
- DbProviderServices.cs
- MenuAdapter.cs
- ModelUtilities.cs
- PropertyDescriptorGridEntry.cs
- StandardCommands.cs
- StatusBarItemAutomationPeer.cs
- XmlSignificantWhitespace.cs
- StreamSecurityUpgradeAcceptorAsyncResult.cs
- ObjectTag.cs
- DataListItemCollection.cs
- SspiNegotiationTokenProviderState.cs
- SiteMembershipCondition.cs
- CursorInteropHelper.cs
- WebZone.cs
- Empty.cs
- Collection.cs
- WebConfigurationHostFileChange.cs
- BufferBuilder.cs
- FixUpCollection.cs
- ListItemCollection.cs
- SiteMapDataSourceView.cs
- DelegatingChannelListener.cs
- SymbolMethod.cs
- SessionParameter.cs
- EventProvider.cs
- RootContext.cs
- panel.cs
- RuntimeEnvironment.cs
- SqlUDTStorage.cs
- categoryentry.cs
- BaseProcessProtocolHandler.cs
- ListBox.cs
- HtmlAnchor.cs
- BamlResourceSerializer.cs
- TransformerConfigurationWizardBase.cs
- TemplateParser.cs
- NameSpaceExtractor.cs
- CalendarDataBindingHandler.cs
- Brush.cs
- DataContractAttribute.cs
- NativeMethods.cs
- StrokeNodeOperations.cs
- RoutingBehavior.cs
- XsltCompileContext.cs
- XappLauncher.cs
- MouseButtonEventArgs.cs
- ProfileService.cs
- complextypematerializer.cs
- Interlocked.cs
- ShaperBuffers.cs
- StrokeSerializer.cs
- TileBrush.cs
- Menu.cs