1 //------------------------------------------------------------------------------
2 // <copyright file="HttpRuntime.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
8 * The ASP.NET runtime services
10 * Copyright (c) 1998 Microsoft Corporation
13 namespace System.Web {
15 using System.Collections;
16 using System.Configuration;
18 using System.Data.Common;
19 using System.Diagnostics.CodeAnalysis;
20 using System.Globalization;
23 using System.Reflection;
24 using System.Resources;
26 using System.Runtime.InteropServices;
27 using System.Runtime.Remoting.Messaging;
28 using System.Security;
29 using System.Security.Cryptography;
30 using System.Security.Permissions;
31 using System.Security.Policy;
32 using System.Security.Principal;
34 using System.Threading;
36 using System.Web.Caching;
37 using System.Web.Compilation;
38 using System.Web.Configuration;
39 using System.Web.Hosting;
40 using System.Web.Management;
41 using System.Web.Security;
43 using System.Web.Util;
45 using Microsoft.Win32;
48 /// <para>Provides a set of ASP.NET runtime services.</para>
50 public sealed class HttpRuntime {
52 internal const string codegenDirName = "Temporary ASP.NET Files";
53 internal const string profileFileName = "profileoptimization.prof";
55 private static HttpRuntime _theRuntime; // single instance of the class
56 internal static byte[] s_autogenKeys = new byte[1024];
59 // Names of special ASP.NET directories
62 internal const string BinDirectoryName = "bin";
63 internal const string CodeDirectoryName = "App_Code";
64 internal const string WebRefDirectoryName = "App_WebReferences";
65 internal const string ResourcesDirectoryName = "App_GlobalResources";
66 internal const string LocalResourcesDirectoryName = "App_LocalResources";
67 internal const string DataDirectoryName = "App_Data";
68 internal const string ThemesDirectoryName = "App_Themes";
69 internal const string GlobalThemesDirectoryName = "Themes";
70 internal const string BrowsersDirectoryName = "App_Browsers";
72 private static string DirectorySeparatorString = new string(Path.DirectorySeparatorChar, 1);
73 private static string DoubleDirectorySeparatorString = new string(Path.DirectorySeparatorChar, 2);
74 private static char[] s_InvalidPhysicalPathChars = { '/', '?', '*', '<', '>', '|', '"' };
79 // For s_forbiddenDirs and s_forbiddenDirsConstant, see
80 // ndll.h, and RestrictIISFolders in regiis.cxx
82 internal static string[] s_forbiddenDirs = {
86 ResourcesDirectoryName,
90 internal static Int32[] s_forbiddenDirsConstant = {
91 UnsafeNativeMethods.RESTRICT_BIN,
92 UnsafeNativeMethods.RESTRICT_CODE,
93 UnsafeNativeMethods.RESTRICT_DATA,
94 UnsafeNativeMethods.RESTRICT_RESOURCES,
95 UnsafeNativeMethods.RESTRICT_WEBREFERENCES,
99 static HttpRuntime() {
100 AddAppDomainTraceMessage("*HttpRuntime::cctor");
104 _theRuntime = new HttpRuntime();
108 AddAppDomainTraceMessage("HttpRuntime::cctor*");
111 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
112 public HttpRuntime() {
116 // static initialization to get hooked up to the unmanaged code
117 // get installation directory, etc.
120 private static bool s_initialized = false;
121 private static String s_installDirectory;
122 private static bool s_isEngineLoaded = false;
124 // Force the static initialization of this class.
125 internal static void ForceStaticInit() { }
127 private static void StaticInit() {
129 // already initialized
133 bool isEngineLoaded = false;
134 bool wasEngineLoadedHere = false;
135 String installDir = null;
137 // load webengine.dll if it is not loaded already
139 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
141 installDir = RuntimeEnvironment.GetRuntimeDirectory();
143 if (UnsafeNativeMethods.GetModuleHandle(ModName.ENGINE_FULL_NAME) != IntPtr.Zero) {
144 isEngineLoaded = true;
147 // Load webengine.dll if not loaded already
149 if (!isEngineLoaded) {
150 String fullPath = installDir + Path.DirectorySeparatorChar + ModName.ENGINE_FULL_NAME;
152 if (UnsafeNativeMethods.LoadLibrary(fullPath) != IntPtr.Zero) {
153 isEngineLoaded = true;
154 wasEngineLoadedHere = true;
158 if (isEngineLoaded) {
159 UnsafeNativeMethods.InitializeLibrary(false);
161 if (wasEngineLoadedHere) {
162 UnsafeNativeMethods.PerfCounterInitialize();
166 #else // !FEATURE_PAL
167 string p = typeof(object).Module.FullyQualifiedName;
168 installDir = Path.GetDirectoryName(p);
169 #endif // !FEATURE_PAL
171 s_installDirectory = installDir;
172 s_isEngineLoaded = isEngineLoaded;
173 s_initialized = true;
175 PopulateIISVersionInformation();
177 AddAppDomainTraceMessage("Initialize");
184 private NamedPermissionSet _namedPermissionSet;
185 private PolicyLevel _policyLevel;
186 private string _hostSecurityPolicyResolverType = null;
187 private FileChangesMonitor _fcm;
188 private CacheInternal _cacheInternal;
189 private Cache _cachePublic;
190 private bool _isOnUNCShare;
191 private Profiler _profiler;
192 private RequestTimeoutManager _timeoutManager;
193 private RequestQueue _requestQueue;
194 private bool _apartmentThreading;
196 private bool _processRequestInApplicationTrust;
197 private bool _disableProcessRequestInApplicationTrust;
198 private bool _isLegacyCas;
203 private bool _beforeFirstRequest = true;
204 private DateTime _firstRequestStartTime;
205 private bool _firstRequestCompleted;
206 private bool _userForcedShutdown;
207 private bool _configInited;
208 private bool _fusionInited;
209 private int _activeRequestCount;
210 private volatile bool _disposingHttpRuntime;
211 private DateTime _lastShutdownAttemptTime;
212 private bool _shutdownInProgress;
213 private String _shutDownStack;
214 private String _shutDownMessage;
215 private ApplicationShutdownReason _shutdownReason = ApplicationShutdownReason.None;
216 private string _trustLevel;
217 private string _wpUserId;
218 private bool _shutdownWebEventRaised;
223 private bool _enableHeaderChecking;
229 private AsyncCallback _requestNotificationCompletionCallback;
230 private AsyncCallback _handlerCompletionCallback;
231 private HttpWorkerRequest.EndOfSendNotification _asyncEndOfSendCallback;
232 private WaitCallback _appDomainUnloadallback;
235 // Initialization error (to be reported on subsequent requests)
238 private Exception _initializationError;
239 private bool _hostingInitFailed; // make such errors non-sticky
240 private Timer _appDomainShutdownTimer = null;
244 // App domain related
247 private String _tempDir;
248 private String _codegenDir;
249 private String _appDomainAppId;
250 private String _appDomainAppPath;
251 private VirtualPath _appDomainAppVPath;
252 private String _appDomainId;
258 private bool _debuggingEnabled = false;
261 // App_Offline.htm support
264 private const string AppOfflineFileName = "App_Offline.htm";
265 private const long MaxAppOfflineFileLength = 1024 * 1024;
266 private byte[] _appOfflineMessage;
269 // Client script support
272 private const string AspNetClientFilesSubDirectory = "asp.netclientfiles";
273 private const string AspNetClientFilesParentVirtualPath = "/aspnet_client/system_web/";
274 private string _clientScriptVirtualPath;
275 private string _clientScriptPhysicalPath;
278 // IIS version and whether we're using the integrated pipeline
280 private static Version _iisVersion;
281 private static bool _useIntegratedPipeline;
286 private static bool _enablePrefetchOptimization;
288 /////////////////////////////////////////////////////////////////////////
289 // 3 steps of initialization:
290 // Init() is called from HttpRuntime cctor
291 // HostingInit() is called by the Hosting Environment
292 // FirstRequestInit() is called on first HTTP request
296 * Context-less initialization (on app domain creation)
298 private void Init() {
301 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
302 throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT));
303 #else // !FEATURE_PAL
305 // Do nothing: FEATURE_PAL environment will always support ASP.NET hosting
306 #endif // !FEATURE_PAL
308 _profiler = new Profiler();
309 _timeoutManager = new RequestTimeoutManager();
310 _wpUserId = GetCurrentUserName();
312 _requestNotificationCompletionCallback = new AsyncCallback(this.OnRequestNotificationCompletion);
313 _handlerCompletionCallback = new AsyncCallback(this.OnHandlerCompletion);
314 _asyncEndOfSendCallback = new HttpWorkerRequest.EndOfSendNotification(this.EndOfSendCallback);
315 _appDomainUnloadallback = new WaitCallback(this.ReleaseResourcesAndUnloadAppDomain);
319 if (GetAppDomainString(".appDomain") != null) {
321 Debug.Assert(HostingEnvironment.IsHosted);
323 _appDomainAppId = GetAppDomainString(".appId");
324 _appDomainAppPath = GetAppDomainString(".appPath");
325 _appDomainAppVPath = VirtualPath.CreateNonRelativeTrailingSlash(GetAppDomainString(".appVPath"));
326 _appDomainId = GetAppDomainString(".domainId");
328 _isOnUNCShare = StringUtil.StringStartsWith(_appDomainAppPath, "\\\\");
330 // init perf counters for this appdomain
331 PerfCounters.Open(_appDomainAppId);
334 Debug.Assert(!HostingEnvironment.IsHosted);
337 // _appDomainAppPath should be set before file change notifications are initialized
338 // DevDiv 248126: Check httpRuntime fcnMode first before we use the registry key
339 _fcm = new FileChangesMonitor(HostingEnvironment.FcnMode);
341 catch (Exception e) {
342 // remember static initalization error
343 InitializationException = e;
347 private void SetUpDataDirectory() {
349 // Set the DataDirectory (see VSWhidbey 226834) with permission (DevDiv 29614)
350 string dataDirectory = Path.Combine(_appDomainAppPath, DataDirectoryName);
351 AppDomain.CurrentDomain.SetData("DataDirectory", dataDirectory,
352 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dataDirectory));
355 private void DisposeAppDomainShutdownTimer() {
356 Timer timer = _appDomainShutdownTimer;
357 if (timer != null && Interlocked.CompareExchange(ref _appDomainShutdownTimer, null, timer) == timer) {
362 private void AppDomainShutdownTimerCallback(Object state) {
364 DisposeAppDomainShutdownTimer();
365 ShutdownAppDomain(ApplicationShutdownReason.InitializationError, "Initialization Error");
367 catch { } // ignore exceptions
371 * Restart the AppDomain in 10 seconds
373 private void StartAppDomainShutdownTimer() {
374 if (_appDomainShutdownTimer == null && !_shutdownInProgress) {
376 if (_appDomainShutdownTimer == null && !_shutdownInProgress) {
377 _appDomainShutdownTimer = new Timer(
378 new TimerCallback(this.AppDomainShutdownTimerCallback),
389 * Initialization from HostingEnvironment of HTTP independent features
391 private void HostingInit(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) {
392 using (new ApplicationImpersonationContext()) {
394 // To ignore FCN during initialization
395 _firstRequestStartTime = DateTime.UtcNow;
397 SetUpDataDirectory();
399 // Throw an exception about lack of access to app directory early on
400 EnsureAccessToApplicationDirectory();
402 // Monitor renames to directories we are watching, and notifications on the bin directory
404 // Note that this must be the first monitoring that we do of the application directory.
410 StartMonitoringDirectoryRenamesAndBinDirectory();
412 // Initialize ObjectCacheHost before config is read, since config relies on the cache
413 if (InitializationException == null) {
414 HostingEnvironment.InitializeObjectCacheHost();
418 // Get the configuration needed to minimally initialize
419 // the components required for a complete configuration system,
420 // especially SetTrustLevel.
422 // We want to do this before calling SetUpCodegenDirectory(),
423 // to remove the risk of the config system loading
424 // codegen assemblies in full trust (VSWhidbey 460506)
426 CacheSection cacheSection;
427 TrustSection trustSection;
428 SecurityPolicySection securityPolicySection;
429 CompilationSection compilationSection;
430 HostingEnvironmentSection hostingEnvironmentSection;
431 Exception configInitException;
433 GetInitConfigSections(
436 out securityPolicySection,
437 out compilationSection,
438 out hostingEnvironmentSection,
439 out configInitException);
441 // Once the configuration system is initialized, we can read
442 // the cache configuration settings.
444 // Note that we must do this after we start monitoring directory renames,
445 // as reading config will cause file monitoring on the application directory
447 HttpRuntime.CacheInternal.ReadCacheInternalConfig(cacheSection);
449 // Set up the codegen directory for the app. This needs to be done before we process
450 // the policy file, because it needs to replace the $CodeGen$ token.
451 SetUpCodegenDirectory(compilationSection);
453 if(compilationSection != null) {
454 _enablePrefetchOptimization = compilationSection.EnablePrefetchOptimization;
455 if(_enablePrefetchOptimization) {
456 UnsafeNativeMethods.StartPrefetchActivity((uint)StringUtil.GetStringHashCode(_appDomainAppId));
460 // NOTE: after calling SetUpCodegenDirectory(), and until we call SetTrustLevel(), we are at
461 // risk of codegen assemblies being loaded in full trust. No code that might cause
462 // assembly loading should be added here! This is only valid if the legacyCasModel is set
463 // to true in <trust> section.
465 // Throw the original configuration exception from ApplicationManager if configuration is broken.
466 if (appDomainCreationException != null) {
467 throw appDomainCreationException;
470 if (trustSection == null || String.IsNullOrEmpty(trustSection.Level)) {
471 throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "trust"));
474 if (trustSection.LegacyCasModel) {
476 _disableProcessRequestInApplicationTrust = false;
478 // Set code access policy on the app domain
479 SetTrustLevel(trustSection, securityPolicySection);
482 // throw the original config exception if it exists
483 if (configInitException != null)
484 throw configInitException;
488 else if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
489 _trustLevel = "Full";
492 _disableProcessRequestInApplicationTrust = true;
493 // Set code access policy properties of the runtime object
494 SetTrustParameters(trustSection, securityPolicySection, policyLevel);
497 // Configure fusion to use directories set in the app config
498 InitFusion(hostingEnvironmentSection);
500 // set the sliding expiration for URL metadata
501 CachedPathData.InitializeUrlMetadataSlidingExpiration(hostingEnvironmentSection);
503 // Complete initialization of configuration.
504 // Note that this needs to be called after SetTrustLevel,
505 // as it indicates that we have the permission set needed
506 // to correctly run configuration section handlers.
507 // As little config should be read before CompleteInit() as possible.
508 // No section that runs before CompleteInit() should demand permissions,
509 // as the permissions set has not yet determined until SetTrustLevel()
511 HttpConfigurationSystem.CompleteInit();
514 // If an exception occurred loading configuration,
515 // we are now ready to handle exception processing
516 // with the correct trust level set.
518 if (configInitException != null) {
519 throw configInitException;
522 SetThreadPoolLimits();
526 // Initialize the build manager
527 BuildManager.InitializeBuildManager();
529 if(compilationSection != null && compilationSection.ProfileGuidedOptimizations == ProfileGuidedOptimizationsFlags.All) {
530 ProfileOptimization.SetProfileRoot(_codegenDir);
531 ProfileOptimization.StartProfile(profileFileName);
534 // Determine apartment threading setting
535 InitApartmentThreading();
538 InitDebuggingSupport();
540 _processRequestInApplicationTrust = trustSection.ProcessRequestInApplicationTrust;
542 // Init AppDomain Resource Perf Counters
543 AppDomainResourcePerfCounters.Init();
546 RelaxMapPathIfRequired();
548 catch (Exception e) {
549 _hostingInitFailed = true;
550 InitializationException = e;
552 Debug.Trace("AppDomainFactory", "HostingInit failed. " + e.ToString());
554 if ((hostingFlags & HostingEnvironmentFlags.ThrowHostingInitErrors) != 0)
560 internal static Exception InitializationException {
562 return _theRuntime._initializationError;
565 // The exception is "cached" for 10 seconds, then the AppDomain is restarted.
567 _theRuntime._initializationError = value;
568 // In v2.0, we shutdown immediately if hostingInitFailed...so we don't need the timer
569 if (!HostingInitFailed) {
570 _theRuntime.StartAppDomainShutdownTimer();
575 internal static bool HostingInitFailed {
577 return _theRuntime._hostingInitFailed;
581 internal static void InitializeHostingFeatures(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) {
582 _theRuntime.HostingInit(hostingFlags, policyLevel, appDomainCreationException);
585 internal static bool EnableHeaderChecking {
587 return _theRuntime._enableHeaderChecking;
591 internal static bool ProcessRequestInApplicationTrust {
593 return _theRuntime._processRequestInApplicationTrust;
597 internal static bool DisableProcessRequestInApplicationTrust {
599 return _theRuntime._disableProcessRequestInApplicationTrust;
603 internal static bool IsLegacyCas {
605 return _theRuntime._isLegacyCas;
609 internal static byte[] AppOfflineMessage {
611 return _theRuntime._appOfflineMessage;
616 * Initialization on first request (context available)
618 private void FirstRequestInit(HttpContext context) {
619 Exception error = null;
621 if (InitializationException == null && _appDomainId != null) {
623 HttpContext.SetDebugAssertOnAccessToCurrent(true);
626 using (new ApplicationImpersonationContext()) {
627 // Is this necessary? See InitHttpConfiguration
628 CultureInfo savedCulture = Thread.CurrentThread.CurrentCulture;
629 CultureInfo savedUICulture = Thread.CurrentThread.CurrentUICulture;
632 // Ensure config system is initialized
633 InitHttpConfiguration(); // be sure config system is set
635 // Check if applicaton is enabled
636 CheckApplicationEnabled();
638 // Check access to temp compilation directory (under hosting identity)
639 CheckAccessToTempDirectory();
641 // Initialize health monitoring
642 InitializeHealthMonitoring();
644 // Init request queue (after reading config)
647 // configure the profiler according to config
650 // Start heatbeat for Web Event Health Monitoring
651 HealthMonitoringManager.StartHealthMonitoringHeartbeat();
653 // Remove read and browse access of the bin directory
654 RestrictIISFolders(context);
656 // Preload all assemblies from bin (only if required). ASURT 114486
657 PreloadAssembliesFromBin();
659 // Decide whether or not to encode headers. VsWhidbey 257154
660 InitHeaderEncoding();
662 // Force the current encoder + validator to load so that there's a deterministic
663 // place (here) for an exception to occur if there's a load error
664 HttpEncoder.InitializeOnFirstRequest();
665 RequestValidator.InitializeOnFirstRequest();
667 if (context.WorkerRequest is ISAPIWorkerRequestOutOfProc) {
668 // Make sure that the <processModel> section has no errors
669 ProcessModelSection processModel = RuntimeConfig.GetMachineConfig().ProcessModel;
673 Thread.CurrentThread.CurrentUICulture = savedUICulture;
674 SetCurrentThreadCultureWithAssert(savedCulture);
678 catch (ConfigurationException e) {
681 catch (Exception e) {
682 // remember second-phase initialization error
683 error = new HttpException(SR.GetString(SR.XSP_init_error, e.Message), e);
687 HttpContext.SetDebugAssertOnAccessToCurrent(false);
692 if (InitializationException != null) {
693 // throw cached exception. We need to wrap it in a new exception, otherwise
694 // we lose the original stack.
695 throw new HttpException(InitializationException.Message, InitializationException);
697 else if (error != null) {
698 InitializationException = error;
699 // throw new exception
703 AddAppDomainTraceMessage("FirstRequestInit");
706 [SecurityPermission(SecurityAction.Assert, ControlThread = true)]
707 internal static void SetCurrentThreadCultureWithAssert(CultureInfo cultureInfo) {
708 Thread.CurrentThread.CurrentCulture = cultureInfo;
711 private void EnsureFirstRequestInit(HttpContext context) {
712 if (_beforeFirstRequest) {
714 if (_beforeFirstRequest) {
715 _firstRequestStartTime = DateTime.UtcNow;
716 FirstRequestInit(context);
717 _beforeFirstRequest = false;
718 context.FirstRequest = true;
724 private void EnsureAccessToApplicationDirectory() {
725 if (!FileUtil.DirectoryAccessible(_appDomainAppPath)) {
727 if (_appDomainAppPath.IndexOf('?') >= 0) {
728 // Possible Unicode when not supported
729 throw new HttpException(SR.GetString(SR.Access_denied_to_unicode_app_dir, _appDomainAppPath));
732 throw new HttpException(SR.GetString(SR.Access_denied_to_app_dir, _appDomainAppPath));
737 private void StartMonitoringDirectoryRenamesAndBinDirectory() {
738 _fcm.StartMonitoringDirectoryRenamesAndBinDirectory(AppDomainAppPathInternal, new FileChangeEventHandler(this.OnCriticalDirectoryChange));
742 // Monitor a local resources subdirectory and unload appdomain when it changes
744 internal static void StartListeningToLocalResourcesDirectory(VirtualPath virtualDir) {
745 #if !FEATURE_PAL // FEATURE_PAL does not enable file change notification
746 _theRuntime._fcm.StartListeningToLocalResourcesDirectory(virtualDir);
747 #endif // !FEATURE_PAL
751 // Get the configuration needed to minimally initialize
752 // the components required for a complete configuration system,
754 // Note that if the application configuration file has an error,
755 // AppLKGConfig will still retreive any valid configuration from
756 // that file, or from location directives that apply to the
757 // application path. This implies that an administrator can
758 // lock down an application's trust level in root web.config,
759 // and it will still take effect if the application's web.config
762 private void GetInitConfigSections(
763 out CacheSection cacheSection,
764 out TrustSection trustSection,
765 out SecurityPolicySection securityPolicySection,
766 out CompilationSection compilationSection,
767 out HostingEnvironmentSection hostingEnvironmentSection,
768 out Exception initException) {
772 securityPolicySection = null;
773 compilationSection = null;
774 hostingEnvironmentSection = null;
775 initException = null;
777 // AppLKGConfig is guaranteed to not throw an exception.
778 RuntimeConfig appLKGConfig = RuntimeConfig.GetAppLKGConfig();
780 // AppConfig may throw an exception.
781 RuntimeConfig appConfig = null;
783 appConfig = RuntimeConfig.GetAppConfig();
785 catch (Exception e) {
790 if (appConfig != null) {
792 cacheSection = appConfig.Cache;
794 catch (Exception e) {
795 if (initException == null) {
801 if (cacheSection == null) {
802 cacheSection = appLKGConfig.Cache;
806 if (appConfig != null) {
808 trustSection = appConfig.Trust;
810 catch (Exception e) {
811 if (initException == null) {
817 if (trustSection == null) {
818 trustSection = appLKGConfig.Trust;
821 // SecurityPolicy section
822 if (appConfig != null) {
824 securityPolicySection = appConfig.SecurityPolicy;
826 catch (Exception e) {
827 if (initException == null) {
833 if (securityPolicySection == null) {
834 securityPolicySection = appLKGConfig.SecurityPolicy;
837 // Compilation section
838 if (appConfig != null) {
840 compilationSection = appConfig.Compilation;
842 catch (Exception e) {
843 if (initException == null) {
849 if (compilationSection == null) {
850 compilationSection = appLKGConfig.Compilation;
853 // HostingEnvironment section
854 if (appConfig != null) {
856 hostingEnvironmentSection = appConfig.HostingEnvironment;
858 catch (Exception e) {
859 if (initException == null) {
865 if (hostingEnvironmentSection == null) {
866 hostingEnvironmentSection = appLKGConfig.HostingEnvironment;
870 // Set up the codegen directory for the app
871 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This call site is trusted.")]
872 private void SetUpCodegenDirectory(CompilationSection compilationSection) {
873 AppDomain appDomain = Thread.GetDomain();
877 // devdiv 1038337. Passing the corresponding IsDevelopmentEnvironment flag to ConstructSimpleAppName
878 string simpleAppName = System.Web.Hosting.AppManagerAppDomainFactory.ConstructSimpleAppName(
879 AppDomainAppVirtualPath, HostingEnvironment.IsDevelopmentEnvironment);
881 string tempDirectory = null;
883 // These variables are used for error handling
884 string tempDirAttribName = null;
885 string configFileName = null;
886 int configLineNumber = 0;
888 if (compilationSection != null && !String.IsNullOrEmpty(compilationSection.TempDirectory)) {
889 tempDirectory = compilationSection.TempDirectory;
891 compilationSection.GetTempDirectoryErrorInfo(out tempDirAttribName,
892 out configFileName, out configLineNumber);
895 if (tempDirectory != null) {
896 tempDirectory = tempDirectory.Trim();
898 if (!Path.IsPathRooted(tempDirectory)) {
899 // Make sure the path is not relative (VSWhidbey 260075)
900 tempDirectory = null;
904 // Canonicalize it to avoid problems with spaces (VSWhidbey 229873)
905 tempDirectory = new DirectoryInfo(tempDirectory).FullName;
908 tempDirectory = null;
912 if (tempDirectory == null) {
913 throw new ConfigurationErrorsException(
914 SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
915 configFileName, configLineNumber);
919 System.UInt32 length = 0;
920 StringBuilder sb = null;
923 // Get the required length
924 bRet = UnsafeNativeMethods.GetUserTempDirectory(
925 UnsafeNativeMethods.DeploymentDirectoryType.ddtInstallationDependentDirectory,
929 // now, allocate the string
930 sb = new StringBuilder ((int)length);
932 // call again to get the value
933 bRet = UnsafeNativeMethods.GetUserTempDirectory(
934 UnsafeNativeMethods.DeploymentDirectoryType.ddtInstallationDependentDirectory,
939 throw new ConfigurationException(
940 HttpRuntime.FormatResourceString(SR.Invalid_temp_directory, tempDirAttribName));
943 tempDirectory = Path.Combine(sb.ToString(), codegenDirName);
946 // Always try to create the ASP.Net temp directory for FEATURE_PAL
947 #endif // FEATURE_PAL
949 // Create the config-specified directory if needed
951 Directory.CreateDirectory(tempDirectory);
953 catch (Exception e) {
954 throw new ConfigurationErrorsException(
955 SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
957 configFileName, configLineNumber);
962 tempDirectory = Path.Combine(s_installDirectory, codegenDirName);
964 #endif // !FEATURE_PAL
966 // If we don't have write access to the codegen dir, use the TEMP dir instead.
967 // This will allow non-admin users to work in hosting scenarios (e.g. Venus, aspnet_compiler)
968 if (!System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory)) {
970 // Don't do this if we are not in a CBM scenario and we're in a service (!UserInteractive),
971 // as TEMP could point to unwanted places.
973 #if !FEATURE_PAL // always fail here
974 if ((!BuildManagerHost.InClientBuildManager) && (!Environment.UserInteractive))
975 #endif // !FEATURE_PAL
977 throw new HttpException(SR.GetString(SR.No_codegen_access,
978 System.Web.UI.Util.GetCurrentAccountName(), tempDirectory));
981 tempDirectory = Path.GetTempPath();
982 Debug.Assert(System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory));
983 tempDirectory = Path.Combine(tempDirectory, codegenDirName);
986 _tempDir = tempDirectory;
988 codegenBase = Path.Combine(tempDirectory, simpleAppName);
990 #pragma warning disable 0618 // To avoid deprecation warning
991 appDomain.SetDynamicBase(codegenBase);
992 #pragma warning restore 0618
994 _codegenDir = Thread.GetDomain().DynamicDirectory;
996 // Create the codegen directory if needed
997 Directory.CreateDirectory(_codegenDir);
1000 private void InitFusion(HostingEnvironmentSection hostingEnvironmentSection) {
1002 AppDomain appDomain = Thread.GetDomain();
1004 // If there is a double backslash in the string, get rid of it (ASURT 122191)
1005 // Make sure to skip the first char, to avoid breaking the UNC case
1006 string appDomainAppPath = _appDomainAppPath;
1007 if (appDomainAppPath.IndexOf(DoubleDirectorySeparatorString, 1, StringComparison.Ordinal) >= 1) {
1008 appDomainAppPath = appDomainAppPath[0] + appDomainAppPath.Substring(1).Replace(DoubleDirectorySeparatorString,
1009 DirectorySeparatorString);
1012 #pragma warning disable 0618 // To avoid deprecation warning
1013 // Allow assemblies from 'bin' to be loaded
1014 appDomain.AppendPrivatePath(appDomainAppPath + BinDirectoryName);
1015 #pragma warning restore 0618
1017 // If shadow copying was disabled via config, turn it off (DevDiv 30864)
1018 if (hostingEnvironmentSection != null && !hostingEnvironmentSection.ShadowCopyBinAssemblies) {
1019 #pragma warning disable 0618 // To avoid deprecation warning
1020 appDomain.ClearShadowCopyPath();
1021 #pragma warning restore 0618
1024 // enable shadow-copying from bin
1025 #pragma warning disable 0618 // To avoid deprecation warning
1026 appDomain.SetShadowCopyPath(appDomainAppPath + BinDirectoryName);
1027 #pragma warning restore 0618
1030 // Get rid of the last part of the directory (the app name), since it will
1032 string parentDir = Directory.GetParent(_codegenDir).FullName;
1033 #pragma warning disable 0618 // To avoid deprecation warning
1034 appDomain.SetCachePath(parentDir);
1035 #pragma warning restore 0618
1037 _fusionInited = true;
1040 private void InitRequestQueue() {
1041 RuntimeConfig config = RuntimeConfig.GetAppConfig();
1042 HttpRuntimeSection runtimeConfig = config.HttpRuntime;
1043 ProcessModelSection processConfig = config.ProcessModel;
1045 if (processConfig.AutoConfig) {
1046 _requestQueue = new RequestQueue(
1047 88 * processConfig.CpuCount,
1048 76 * processConfig.CpuCount,
1049 runtimeConfig.AppRequestQueueLimit,
1050 processConfig.ClientConnectedCheck);
1054 // Configuration section handlers cannot validate values based on values
1055 // in other configuration sections, so we validate minFreeThreads and
1056 // minLocalRequestFreeThreads here.
1057 int maxThreads = (processConfig.MaxWorkerThreadsTimesCpuCount < processConfig.MaxIoThreadsTimesCpuCount) ? processConfig.MaxWorkerThreadsTimesCpuCount : processConfig.MaxIoThreadsTimesCpuCount;
1058 // validate minFreeThreads
1059 if (runtimeConfig.MinFreeThreads >= maxThreads) {
1060 if (runtimeConfig.ElementInformation.Properties["minFreeThreads"].LineNumber == 0) {
1061 if (processConfig.ElementInformation.Properties["maxWorkerThreads"].LineNumber != 0) {
1062 throw new ConfigurationErrorsException(SR.GetString(SR.Thread_pool_limit_must_be_greater_than_minFreeThreads, runtimeConfig.MinFreeThreads.ToString(CultureInfo.InvariantCulture)),
1063 processConfig.ElementInformation.Properties["maxWorkerThreads"].Source,
1064 processConfig.ElementInformation.Properties["maxWorkerThreads"].LineNumber);
1067 throw new ConfigurationErrorsException(SR.GetString(SR.Thread_pool_limit_must_be_greater_than_minFreeThreads, runtimeConfig.MinFreeThreads.ToString(CultureInfo.InvariantCulture)),
1068 processConfig.ElementInformation.Properties["maxIoThreads"].Source,
1069 processConfig.ElementInformation.Properties["maxIoThreads"].LineNumber);
1073 throw new ConfigurationErrorsException(SR.GetString(SR.Min_free_threads_must_be_under_thread_pool_limits, maxThreads.ToString(CultureInfo.InvariantCulture)),
1074 runtimeConfig.ElementInformation.Properties["minFreeThreads"].Source,
1075 runtimeConfig.ElementInformation.Properties["minFreeThreads"].LineNumber);
1078 // validate minLocalRequestFreeThreads
1079 if (runtimeConfig.MinLocalRequestFreeThreads > runtimeConfig.MinFreeThreads) {
1080 if (runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].LineNumber == 0) {
1081 throw new ConfigurationErrorsException(SR.GetString(SR.Local_free_threads_cannot_exceed_free_threads),
1082 processConfig.ElementInformation.Properties["minFreeThreads"].Source,
1083 processConfig.ElementInformation.Properties["minFreeThreads"].LineNumber);
1086 throw new ConfigurationErrorsException(SR.GetString(SR.Local_free_threads_cannot_exceed_free_threads),
1087 runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].Source,
1088 runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].LineNumber);
1092 _requestQueue = new RequestQueue(
1093 runtimeConfig.MinFreeThreads,
1094 runtimeConfig.MinLocalRequestFreeThreads,
1095 runtimeConfig.AppRequestQueueLimit,
1096 processConfig.ClientConnectedCheck);
1100 private void InitApartmentThreading() {
1101 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1103 if (runtimeConfig != null) {
1104 _apartmentThreading = runtimeConfig.ApartmentThreading;
1107 _apartmentThreading = false;
1111 private void InitTrace(HttpContext context) {
1112 TraceSection traceConfig = RuntimeConfig.GetAppConfig().Trace;
1114 Profile.RequestsToProfile = traceConfig.RequestLimit;
1115 Profile.PageOutput = traceConfig.PageOutput;
1116 Profile.OutputMode = TraceMode.SortByTime;
1117 if (traceConfig.TraceMode == TraceDisplayMode.SortByCategory)
1118 Profile.OutputMode = TraceMode.SortByCategory;
1120 Profile.LocalOnly = traceConfig.LocalOnly;
1121 Profile.IsEnabled = traceConfig.Enabled;
1122 Profile.MostRecent = traceConfig.MostRecent;
1125 // the first request's context is created before InitTrace, so
1126 // we need to set this manually. (ASURT 93730)
1127 context.TraceIsEnabled = traceConfig.Enabled;
1128 TraceContext.SetWriteToDiagnosticsTrace(traceConfig.WriteToDiagnosticsTrace);
1131 private void InitDebuggingSupport() {
1132 CompilationSection compConfig = RuntimeConfig.GetAppConfig().Compilation;
1133 _debuggingEnabled = compConfig.Debug;
1137 * Pre-load all the bin assemblies if we're impersonated. This way, if user code
1138 * calls Assembly.Load while impersonated, the assembly will already be loaded, and
1139 * we won't fail due to lack of permissions on the codegen dir (see ASURT 114486)
1141 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1142 private void PreloadAssembliesFromBin() {
1143 bool appClientImpersonationEnabled = false;
1145 if (!_isOnUNCShare) {
1146 // if not on UNC share check if config has impersonation enabled (without userName)
1147 IdentitySection c = RuntimeConfig.GetAppConfig().Identity;
1148 if (c.Impersonate && c.ImpersonateToken == IntPtr.Zero)
1149 appClientImpersonationEnabled = true;
1152 if (!appClientImpersonationEnabled)
1155 // Get the path to the bin directory
1156 string binPath = HttpRuntime.BinDirectoryInternal;
1158 DirectoryInfo binPathDirectory = new DirectoryInfo(binPath);
1160 if (!binPathDirectory.Exists)
1163 PreloadAssembliesFromBinRecursive(binPathDirectory);
1166 private void PreloadAssembliesFromBinRecursive(DirectoryInfo dirInfo) {
1168 FileInfo[] binDlls = dirInfo.GetFiles("*.dll");
1170 // Pre-load all the assemblies, ignoring all exceptions
1171 foreach (FileInfo fi in binDlls) {
1172 try { Assembly.Load(System.Web.UI.Util.GetAssemblyNameFromFileName(fi.Name)); }
1173 catch (FileNotFoundException) {
1174 // If Load failed, try LoadFrom (VSWhidbey 493725)
1175 try { Assembly.LoadFrom(fi.FullName); }
1181 // Recurse on the subdirectories
1182 DirectoryInfo[] subDirs = dirInfo.GetDirectories();
1183 foreach (DirectoryInfo di in subDirs) {
1184 PreloadAssembliesFromBinRecursive(di);
1188 private void SetAutoConfigLimits(ProcessModelSection pmConfig) {
1189 // check if the current limits are ok
1190 int workerMax, ioMax;
1191 ThreadPool.GetMaxThreads(out workerMax, out ioMax);
1193 // only set if different
1194 if (pmConfig.DefaultMaxWorkerThreadsForAutoConfig != workerMax || pmConfig.DefaultMaxIoThreadsForAutoConfig != ioMax) {
1195 Debug.Trace("ThreadPool", "SetThreadLimit: from " + workerMax + "," + ioMax + " to " + pmConfig.DefaultMaxWorkerThreadsForAutoConfig + "," + pmConfig.DefaultMaxIoThreadsForAutoConfig);
1196 UnsafeNativeMethods.SetClrThreadPoolLimits(pmConfig.DefaultMaxWorkerThreadsForAutoConfig, pmConfig.DefaultMaxIoThreadsForAutoConfig, true);
1199 // this is the code equivalent of setting maxconnection
1200 // Dev11 141729: Make autoConfig scale by default
1201 // Dev11 144842: PERF: Consider removing Max connection limit or changing the default value
1202 System.Net.ServicePointManager.DefaultConnectionLimit = Int32.MaxValue;
1204 // we call InitRequestQueue later, from FirstRequestInit, and set minFreeThreads and minLocalRequestFreeThreads
1207 private void SetThreadPoolLimits() {
1209 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
1211 if (pmConfig.AutoConfig) {
1212 // use recommendation in http://support.microsoft.com/?id=821268
1213 SetAutoConfigLimits(pmConfig);
1215 else if (pmConfig.MaxWorkerThreadsTimesCpuCount > 0 && pmConfig.MaxIoThreadsTimesCpuCount > 0) {
1216 // check if the current limits are ok
1217 int workerMax, ioMax;
1218 ThreadPool.GetMaxThreads(out workerMax, out ioMax);
1220 // only set if different
1221 if (pmConfig.MaxWorkerThreadsTimesCpuCount != workerMax || pmConfig.MaxIoThreadsTimesCpuCount != ioMax) {
1222 Debug.Trace("ThreadPool", "SetThreadLimit: from " + workerMax + "," + ioMax + " to " + pmConfig.MaxWorkerThreadsTimesCpuCount + "," + pmConfig.MaxIoThreadsTimesCpuCount);
1223 UnsafeNativeMethods.SetClrThreadPoolLimits(pmConfig.MaxWorkerThreadsTimesCpuCount, pmConfig.MaxIoThreadsTimesCpuCount, false);
1227 if (pmConfig.MinWorkerThreadsTimesCpuCount > 0 || pmConfig.MinIoThreadsTimesCpuCount > 0) {
1228 int currentMinWorkerThreads, currentMinIoThreads;
1229 ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIoThreads);
1231 int newMinWorkerThreads = pmConfig.MinWorkerThreadsTimesCpuCount > 0 ? pmConfig.MinWorkerThreadsTimesCpuCount : currentMinWorkerThreads;
1232 int newMinIoThreads = pmConfig.MinIoThreadsTimesCpuCount > 0 ? pmConfig.MinIoThreadsTimesCpuCount : currentMinIoThreads;
1234 if (newMinWorkerThreads > 0 && newMinIoThreads > 0
1235 && (newMinWorkerThreads != currentMinWorkerThreads || newMinIoThreads != currentMinIoThreads))
1236 ThreadPool.SetMinThreads(newMinWorkerThreads, newMinIoThreads);
1243 internal static void CheckApplicationEnabled() {
1244 // process App_Offline.htm file
1245 string appOfflineFile = Path.Combine(_theRuntime._appDomainAppPath, AppOfflineFileName);
1246 bool appOfflineFileFound = false;
1248 // monitor even if doesn't exist
1249 _theRuntime._fcm.StartMonitoringFile(appOfflineFile, new FileChangeEventHandler(_theRuntime.OnAppOfflineFileChange));
1251 // read the file into memory
1253 if (File.Exists(appOfflineFile)) {
1254 Debug.Trace("AppOffline", "File " + appOfflineFile + " exists. Using it.");
1256 using (FileStream fs = new FileStream(appOfflineFile, FileMode.Open, FileAccess.Read, FileShare.Read)) {
1257 if (fs.Length <= MaxAppOfflineFileLength) {
1258 int length = (int)fs.Length;
1261 byte[] message = new byte[length];
1263 if (fs.Read(message, 0, length) == length) {
1264 // remember the message
1265 _theRuntime._appOfflineMessage = message;
1266 appOfflineFileFound = true;
1271 appOfflineFileFound = true;
1272 _theRuntime._appOfflineMessage = new byte[0];
1279 // ignore any IO errors reading the file
1282 // throw if there is a valid App_Offline file
1283 if (appOfflineFileFound) {
1284 throw new HttpException(503, String.Empty);
1287 // process the config setting
1288 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1289 if (!runtimeConfig.Enable) {
1290 // throw 404 on first request init -- this will get cached until config changes
1291 throw new HttpException(404, String.Empty);
1295 [FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
1296 private void CheckAccessToTempDirectory() {
1297 // The original check (in HostingInit) was done under process identity
1298 // this time we do it under hosting identity
1299 if (HostingEnvironment.HasHostingIdentity) {
1300 using (new ApplicationImpersonationContext()) {
1301 if (!System.Web.UI.Util.HasWriteAccessToDirectory(_tempDir)) {
1302 throw new HttpException(SR.GetString(SR.No_codegen_access,
1303 System.Web.UI.Util.GetCurrentAccountName(), _tempDir));
1309 private void InitializeHealthMonitoring() {
1310 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
1311 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
1312 int deadLockInterval = (int)pmConfig.ResponseDeadlockInterval.TotalSeconds;
1313 int requestQueueLimit = pmConfig.RequestQueueLimit;
1314 Debug.Trace("HealthMonitor", "Initalizing: ResponseDeadlockInterval=" + deadLockInterval);
1315 UnsafeNativeMethods.InitializeHealthMonitor(deadLockInterval, requestQueueLimit);
1316 #endif // !FEATURE_PAL
1319 private static void InitHttpConfiguration() {
1320 if (!_theRuntime._configInited) {
1321 _theRuntime._configInited = true;
1323 HttpConfigurationSystem.EnsureInit(null, true, true);
1325 // whenever possible report errors in the user's culture (from machine.config)
1326 // Note: this thread's culture is saved/restored during FirstRequestInit, so this is safe
1329 GlobalizationSection globConfig = RuntimeConfig.GetAppLKGConfig().Globalization;
1330 if (globConfig != null) {
1331 if (!String.IsNullOrEmpty(globConfig.Culture) &&
1332 !StringUtil.StringStartsWithIgnoreCase(globConfig.Culture, "auto"))
1333 SetCurrentThreadCultureWithAssert(HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.Culture));
1335 if (!String.IsNullOrEmpty(globConfig.UICulture) &&
1336 !StringUtil.StringStartsWithIgnoreCase(globConfig.UICulture, "auto"))
1337 Thread.CurrentThread.CurrentUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
1340 // check for errors in <processModel> section
1341 RuntimeConfig appConfig = RuntimeConfig.GetAppConfig();
1342 object section = appConfig.ProcessModel;
1343 // check for errors in <hostingEnvironment> section
1344 section = appConfig.HostingEnvironment;
1348 private void InitHeaderEncoding() {
1349 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1350 _enableHeaderChecking = runtimeConfig.EnableHeaderChecking;
1353 private static void SetAutogenKeys() {
1354 #if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
1355 byte[] bKeysRandom = new byte[s_autogenKeys.Length];
1356 byte[] bKeysStored = new byte[s_autogenKeys.Length];
1357 bool fGetStoredKeys = false;
1358 RNGCryptoServiceProvider randgen = new RNGCryptoServiceProvider();
1360 // Gernerate random keys
1361 randgen.GetBytes(bKeysRandom);
1363 // If getting stored keys via WorkerRequest object failed, get it directly
1364 if (!fGetStoredKeys)
1365 fGetStoredKeys = (UnsafeNativeMethods.EcbCallISAPI(IntPtr.Zero, UnsafeNativeMethods.CallISAPIFunc.GetAutogenKeys,
1366 bKeysRandom, bKeysRandom.Length, bKeysStored, bKeysStored.Length) == 1);
1368 // If we managed to get stored keys, copy them in; else use random keys
1370 Buffer.BlockCopy(bKeysStored, 0, s_autogenKeys, 0, s_autogenKeys.Length);
1372 Buffer.BlockCopy(bKeysRandom, 0, s_autogenKeys, 0, s_autogenKeys.Length);
1373 #endif // !FEATURE_PAL
1376 internal static void IncrementActivePipelineCount() {
1377 Interlocked.Increment(ref _theRuntime._activeRequestCount);
1378 HostingEnvironment.IncrementBusyCount();
1381 internal static void DecrementActivePipelineCount() {
1382 HostingEnvironment.DecrementBusyCount();
1383 Interlocked.Decrement(ref _theRuntime._activeRequestCount);
1386 internal static void PopulateIISVersionInformation() {
1387 if (IsEngineLoaded) {
1389 bool fIsIntegratedMode;
1390 UnsafeIISMethods.MgdGetIISVersionInformation(out dwVersion, out fIsIntegratedMode);
1392 if (dwVersion != 0) {
1393 // High word is the major version; low word is the minor version (this is MAKELONG format)
1394 _iisVersion = new Version((int)(dwVersion >> 16), (int)(dwVersion & 0xffff));
1395 _useIntegratedPipeline = fIsIntegratedMode;
1400 // Gets the version of IIS (7.0, 7.5, 8.0, etc.) that is hosting this application, or null if this application isn't IIS-hosted.
1401 // Should also return the correct version for IIS Express.
1402 public static Version IISVersion {
1408 // DevDivBugs 190952: public method for querying runtime pipeline mode
1409 public static bool UsingIntegratedPipeline {
1411 return UseIntegratedPipeline;
1415 internal static bool UseIntegratedPipeline {
1417 return _useIntegratedPipeline;
1421 internal static bool EnablePrefetchOptimization {
1423 return _enablePrefetchOptimization;
1428 * Process one step of the integrated pipeline
1432 internal static RequestNotificationStatus ProcessRequestNotification(IIS7WorkerRequest wr, HttpContext context)
1434 return _theRuntime.ProcessRequestNotificationPrivate(wr, context);
1437 private RequestNotificationStatus ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) {
1438 RequestNotificationStatus status = RequestNotificationStatus.Pending;
1440 int currentModuleIndex;
1441 bool isPostNotification;
1442 int currentNotification;
1444 // setup the HttpContext for this event/module combo
1445 UnsafeIISMethods.MgdGetCurrentNotificationInfo(wr.RequestContext, out currentModuleIndex, out isPostNotification, out currentNotification);
1447 context.CurrentModuleIndex = currentModuleIndex;
1448 context.IsPostNotification = isPostNotification;
1449 context.CurrentNotification = (RequestNotification) currentNotification;
1451 Debug.Trace("PipelineRuntime", "HttpRuntime::ProcessRequestNotificationPrivate: notification=" + context.CurrentNotification.ToString()
1452 + ", isPost=" + context.IsPostNotification
1453 + ", moduleIndex=" + context.CurrentModuleIndex);
1456 IHttpHandler handler = null;
1457 if (context.NeedToInitializeApp()) {
1459 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
1460 "*** FirstNotification " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
1461 + ": _appDomainAppId=" + _appDomainAppId);
1463 // First request initialization
1465 EnsureFirstRequestInit(context);
1468 // If we are handling a DEBUG request, ignore the FirstRequestInit exception.
1469 // This allows the HttpDebugHandler to execute, and lets the debugger attach to
1470 // the process (VSWhidbey 358135)
1471 if (!context.Request.IsDebuggingRequest) {
1476 context.Response.InitResponseWriter();
1477 handler = HttpApplicationFactory.GetApplicationInstance(context);
1478 if (handler == null)
1479 throw new HttpException(SR.GetString(SR.Unable_create_app_object));
1481 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, handler.GetType().FullName, "Start");
1483 HttpApplication app = handler as HttpApplication;
1485 // associate the context with an application instance
1486 app.AssignContext(context);
1490 // this may throw, and should be called after app initialization
1491 wr.SynchronizeVariables(context);
1493 if (context.ApplicationInstance != null) {
1495 IAsyncResult ar = context.ApplicationInstance.BeginProcessRequestNotification(context, _requestNotificationCompletionCallback);
1497 if (ar.CompletedSynchronously) {
1498 status = RequestNotificationStatus.Continue;
1501 else if (handler != null) {
1502 // HttpDebugHandler is processed here
1503 handler.ProcessRequest(context);
1504 status = RequestNotificationStatus.FinishRequest;
1507 status = RequestNotificationStatus.Continue;
1510 catch (Exception e) {
1511 status = RequestNotificationStatus.FinishRequest;
1512 context.Response.InitResponseWriter();
1513 // errors are handled in HttpRuntime::FinishRequestNotification
1514 context.AddError(e);
1517 if (status != RequestNotificationStatus.Pending) {
1518 // we completed synchronously
1519 FinishRequestNotification(wr, context, ref status);
1523 Debug.Trace("PipelineRuntime", "HttpRuntime::ProcessRequestNotificationPrivate: status=" + status.ToString());
1529 private void FinishRequestNotification(IIS7WorkerRequest wr, HttpContext context, ref RequestNotificationStatus status) {
1531 Debug.Assert(status != RequestNotificationStatus.Pending, "status != RequestNotificationStatus.Pending");
1533 HttpApplication app = context.ApplicationInstance;
1535 if (context.NotificationContext.RequestCompleted) {
1536 status = RequestNotificationStatus.FinishRequest;
1539 // check if the app offline or whether an error has occurred, and report the condition
1540 context.ReportRuntimeErrorIfExists(ref status);
1542 // we do not return FinishRequest for LogRequest or EndRequest
1543 if (status == RequestNotificationStatus.FinishRequest
1544 && (context.CurrentNotification == RequestNotification.LogRequest
1545 || context.CurrentNotification == RequestNotification.EndRequest)) {
1546 status = RequestNotificationStatus.Continue;
1549 IntPtr requestContext = wr.RequestContext;
1550 bool sendHeaders = UnsafeIISMethods.MgdIsLastNotification(requestContext, status);
1552 context.Response.UpdateNativeResponse(sendHeaders);
1554 catch(Exception e) {
1555 // if we catch an exception here then
1556 // i) clear cached response body bytes on the worker request
1557 // ii) clear the managed headers, the IIS native headers, the mangaged httpwriter response buffers, and the native IIS response buffers
1558 // iii) attempt to format the exception and write it to the response
1559 wr.UnlockCachedResponseBytes();
1560 context.AddError(e);
1561 context.ReportRuntimeErrorIfExists(ref status);
1563 context.Response.UpdateNativeResponse(sendHeaders);
1570 context.FinishPipelineRequest();
1573 // Perf optimization: dispose managed context if possible (no need to try if status is pending)
1574 if (status != RequestNotificationStatus.Pending) {
1575 PipelineRuntime.DisposeHandler(context, requestContext, status);
1579 internal static void FinishPipelineRequest(HttpContext context) {
1580 // Remember that first request is done
1581 _theRuntime._firstRequestCompleted = true;
1583 // need to raise OnRequestCompleted while within the ThreadContext so that things like User, CurrentCulture, etc. are available
1584 context.RaiseOnRequestCompleted();
1586 context.Request.Dispose();
1587 context.Response.Dispose();
1588 HttpApplication app = context.ApplicationInstance;
1590 ThreadContext threadContext = context.IndicateCompletionContext;
1591 if (threadContext != null) {
1592 if (!threadContext.HasBeenDisassociatedFromThread) {
1593 lock (threadContext) {
1594 if (!threadContext.HasBeenDisassociatedFromThread) {
1595 threadContext.DisassociateFromCurrentThread();
1596 context.IndicateCompletionContext = null;
1597 context.InIndicateCompletion = false;
1602 app.ReleaseAppInstance();
1605 SetExecutionTimePerformanceCounter(context);
1606 UpdatePerfCounters(context.Response.StatusCode);
1607 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
1609 // In case of a HostingInit() error, app domain should not stick around
1610 if (HostingInitFailed) {
1611 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of HostingInit error");
1612 ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, "HostingInit error");
1618 * Process one request
1620 private void ProcessRequestInternal(HttpWorkerRequest wr) {
1621 // Count active requests
1622 Interlocked.Increment(ref _activeRequestCount);
1624 if (_disposingHttpRuntime) {
1625 // Dev11 333176: An appdomain is unloaded before all requests are served, resulting in System.AppDomainUnloadedException during isapi completion callback
1627 // HttpRuntim.Dispose could have already finished on a different thread when we had no active requests
1628 // In this case we are about to start or already started unloading the appdomain so we will reject the request the safest way possible
1630 wr.SendStatus(503, "Server Too Busy");
1631 wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
1632 byte[] body = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>");
1633 wr.SendResponseFromMemory(body, body.Length);
1634 // this will flush synchronously because of HttpRuntime.ShutdownInProgress
1635 wr.FlushResponse(true);
1638 Interlocked.Decrement(ref _activeRequestCount);
1643 // Construct the Context on HttpWorkerRequest, hook everything together
1644 HttpContext context;
1647 context = new HttpContext(wr, false /* initResponseWriter */);
1651 // If we fail to create the context for any reason, send back a 400 to make sure
1652 // the request is correctly closed (relates to VSUQFE3962)
1653 wr.SendStatus(400, "Bad Request");
1654 wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
1655 byte[] body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
1656 wr.SendResponseFromMemory(body, body.Length);
1657 wr.FlushResponse(true);
1661 Interlocked.Decrement(ref _activeRequestCount);
1665 wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
1667 HostingEnvironment.IncrementBusyCount();
1670 // First request initialization
1672 EnsureFirstRequestInit(context);
1675 // If we are handling a DEBUG request, ignore the FirstRequestInit exception.
1676 // This allows the HttpDebugHandler to execute, and lets the debugger attach to
1677 // the process (VSWhidbey 358135)
1678 if (!context.Request.IsDebuggingRequest) {
1683 // Init response writer (after we have config in first request init)
1684 // no need for impersonation as it is handled in config system
1685 context.Response.InitResponseWriter();
1687 // Get application instance
1688 IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
1691 throw new HttpException(SR.GetString(SR.Unable_create_app_object));
1693 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName, "Start");
1695 if (app is IHttpAsyncHandler) {
1696 // asynchronous handler
1697 IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
1698 context.AsyncAppHandler = asyncHandler;
1699 asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
1702 // synchronous handler
1703 app.ProcessRequest(context);
1704 FinishRequest(context.WorkerRequest, context, null);
1707 catch (Exception e) {
1708 context.Response.InitResponseWriter();
1709 FinishRequest(wr, context, e);
1713 private void RejectRequestInternal(HttpWorkerRequest wr, bool silent) {
1714 // Construct the Context on HttpWorkerRequest, hook everything together
1715 HttpContext context = new HttpContext(wr, false /* initResponseWriter */);
1716 wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
1718 // Count active requests
1719 Interlocked.Increment(ref _activeRequestCount);
1720 HostingEnvironment.IncrementBusyCount();
1723 context.Response.InitResponseWriter();
1724 FinishRequest(wr, context, null);
1727 PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.REQUESTS_REJECTED);
1728 PerfCounters.IncrementCounter(AppPerfCounter.APP_REQUESTS_REJECTED);
1730 throw new HttpException(503, SR.GetString(SR.Server_too_busy));
1732 catch (Exception e) {
1733 context.Response.InitResponseWriter();
1734 FinishRequest(wr, context, e);
1739 internal static void ReportAppOfflineErrorMessage(HttpResponse response, byte[] appOfflineMessage) {
1740 response.StatusCode = 503;
1741 response.ContentType = "text/html";
1742 response.AddHeader("Retry-After", "3600");
1743 response.OutputStream.Write(appOfflineMessage, 0, appOfflineMessage.Length);
1747 * Finish processing request, sync or async
1749 private void FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) {
1750 HttpResponse response = context.Response;
1752 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
1754 SetExecutionTimePerformanceCounter(context);
1756 // Flush in case of no error
1758 // impersonate around PreSendHeaders / PreSendContent
1759 using (new ClientImpersonationContext(context, false)) {
1761 // this sends the actual content in most cases
1762 response.FinalFlushAtTheEndOfRequestProcessing();
1764 catch (Exception eFlush) {
1770 // Report error if any
1772 using (new DisposableHttpContextWrapper(context)) {
1774 // if the custom encoder throws, it might interfere with returning error information
1775 // to the client, so we force use of the default encoder
1776 context.DisableCustomHttpEncoder = true;
1778 if (_appOfflineMessage != null) {
1780 ReportAppOfflineErrorMessage(response, _appOfflineMessage);
1781 response.FinalFlushAtTheEndOfRequestProcessing();
1787 // when application is on UNC share the code below must
1788 // be run while impersonating the token given by IIS
1789 using (new ApplicationImpersonationContext()) {
1792 // try to report error in a way that could possibly throw (a config exception)
1793 response.ReportRuntimeError(e, true /*canThrow*/, false);
1795 catch (Exception eReport) {
1796 // report the config error in a way that would not throw
1797 response.ReportRuntimeError(eReport, false /*canThrow*/, false);
1800 response.FinalFlushAtTheEndOfRequestProcessing();
1809 // Remember that first request is done
1810 _firstRequestCompleted = true;
1813 // In case we reporting HostingInit() error, app domain should not stick around
1814 if (_hostingInitFailed) {
1815 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of HostingInit error");
1816 ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, "HostingInit error");
1819 // Check status code and increment proper counter
1820 // If it's an error status code (i.e. 400 or higher), increment the proper perf counters
1821 int statusCode = response.StatusCode;
1822 UpdatePerfCounters(statusCode);
1824 context.FinishRequestForCachedPathData(statusCode);
1826 // ---- exceptions from EndOfRequest as they will prevent proper request cleanup
1827 // Since the exceptions are not expected here we want to log them
1831 catch (Exception ex) {
1832 WebBaseEvent.RaiseRuntimeError(ex, this);
1835 // Count active requests
1836 HostingEnvironment.DecrementBusyCount();
1837 Interlocked.Decrement(ref _activeRequestCount);
1839 // Schedule more work if some requests are queued
1840 if (_requestQueue != null)
1841 _requestQueue.ScheduleMoreWorkIfNeeded();
1845 // Make sure shutdown happens only once
1848 private bool InitiateShutdownOnce() {
1849 if (_shutdownInProgress)
1853 if (_shutdownInProgress)
1855 _shutdownInProgress = true;
1862 // Shutdown this and restart new app domain
1864 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1865 private void ReleaseResourcesAndUnloadAppDomain(Object state /*not used*/) {
1867 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
1868 "*** ReleaseResourcesAndUnloadAppDomain " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
1869 + ": _appDomainAppId=" + _appDomainAppId);
1871 Debug.Trace("AppDomainFactory", "ReleaseResourcesAndUnloadAppDomain, Id=" + _appDomainAppId
1872 + " DomainId = " + _appDomainId
1873 + " Stack = " + Environment.StackTrace );
1876 PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.APPLICATION_RESTARTS);
1881 // Release all resources
1890 AddAppDomainTraceMessage("before Unload");
1894 AppDomain.Unload(Thread.GetDomain());
1896 catch (CannotUnloadAppDomainException) {
1897 Debug.Assert(false);
1899 catch (Exception e) {
1900 Debug.Trace("AppDomainFactory", "AppDomain.Unload exception: " + e + "; Id=" + _appDomainAppId);
1901 if (!BuildManagerHost.InClientBuildManager) {
1902 // Avoid calling Exception.ToString if we are in the ClientBuildManager (Dev10
1903 AddAppDomainTraceMessage("Unload Exception: " + e);
1910 private static void SetExecutionTimePerformanceCounter(HttpContext context) {
1911 // Set the Request Execution time perf counter
1912 TimeSpan elapsed = DateTime.UtcNow.Subtract(context.WorkerRequest.GetStartTime());
1913 long milli = elapsed.Ticks / TimeSpan.TicksPerMillisecond;
1915 if (milli > Int32.MaxValue)
1916 milli = Int32.MaxValue;
1918 PerfCounters.SetGlobalCounter(GlobalPerfCounter.REQUEST_EXECUTION_TIME, (int)milli);
1919 PerfCounters.SetCounter(AppPerfCounter.APP_REQUEST_EXEC_TIME, (int)milli);
1922 private static void UpdatePerfCounters(int statusCode) {
1923 if (400 <= statusCode) {
1924 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED);
1925 switch (statusCode) {
1926 case 401: // Not authorized
1927 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_AUTHORIZED);
1929 case 404: // Not found
1930 case 414: // Not found
1931 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);
1936 // If status code is not in the 400-599 range (i.e. 200-299 success or 300-399 redirection),
1937 // count it as a successful request.
1938 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_SUCCEDED);
1942 private void WaitForRequestsToFinish(int waitTimeoutMs) {
1943 DateTime waitLimit = DateTime.UtcNow.AddMilliseconds(waitTimeoutMs);
1946 if (_activeRequestCount == 0 && (_requestQueue == null || _requestQueue.IsEmpty))
1951 // only apply timeout if a managed debugger is not attached
1952 if (!System.Diagnostics.Debugger.IsAttached && DateTime.UtcNow > waitLimit) {
1953 break; // give it up
1959 * Cleanup of all unmananged state
1961 private void Dispose() {
1962 // get shutdown timeout from config
1963 int drainTimeoutSec = HttpRuntimeSection.DefaultShutdownTimeout;
1965 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppLKGConfig().HttpRuntime;
1966 if (runtimeConfig != null) {
1967 drainTimeoutSec = (int)runtimeConfig.ShutdownTimeout.TotalSeconds;
1970 // before aborting compilation give time to drain (new requests are no longer coming at this point)
1971 WaitForRequestsToFinish(drainTimeoutSec * 1000);
1973 // reject remaining queued requests
1974 if (_requestQueue != null)
1975 _requestQueue.Drain();
1977 // By this time all new requests should be directed to a newly created app domain
1978 // But there might be requests that got dispatched to this old app domain but have not reached ProcessRequestInternal yet
1979 // Signal ProcessRequestInternal to reject them immediately without initiating async operations
1980 _disposingHttpRuntime = true;
1983 // give it a little more time to drain
1984 WaitForRequestsToFinish((drainTimeoutSec * 1000) / 6);
1987 // wait for pending async io to complete, prior to aborting requests
1988 // this isn't necessary for IIS 7, where the async sends are always done
1989 // from native code with native buffers
1990 System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.WaitForPendingAsyncIo();
1992 // For IIS7 integrated pipeline, wait until GL_APPLICATION_STOP fires and
1993 // there are no active calls to IndicateCompletion before unloading the AppDomain
1994 if (HttpRuntime.UseIntegratedPipeline) {
1995 PipelineRuntime.WaitForRequestsToDrain();
1998 // wait for all active requests to complete
1999 while (_activeRequestCount != 0) {
2005 // Dispose AppDomainShutdownTimer
2006 DisposeAppDomainShutdownTimer();
2008 // kill all remaining requests (and the timeout timer)
2009 _timeoutManager.Stop();
2010 AppDomainResourcePerfCounters.Stop();
2012 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
2013 // double check for pending async io
2014 System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.WaitForPendingAsyncIo();
2016 // stop sqlcachedependency polling
2017 SqlCacheDependencyManager.Dispose((drainTimeoutSec * 1000) / 2);
2018 #endif // !FEATURE_PAL
2019 // cleanup cache (this ends all sessions)
2020 if (_cacheInternal != null) {
2021 _cacheInternal.Dispose();
2024 // app on end, cleanup app instances
2025 HttpApplicationFactory.EndApplication(); // call app_onEnd
2027 // stop file changes monitor
2030 // stop health monitoring timer
2031 HealthMonitoringManager.Shutdown();
2035 * Async completion of IIS7 pipeline (unlike OnHandlerCompletion, this may fire more than once).
2037 private void OnRequestNotificationCompletion(IAsyncResult ar) {
2039 OnRequestNotificationCompletionHelper(ar);
2041 catch(Exception e) {
2042 ApplicationManager.RecordFatalException(e);
2047 private void OnRequestNotificationCompletionHelper(IAsyncResult ar) {
2048 if (ar.CompletedSynchronously) {
2049 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion: completed synchronously");
2053 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion: completed asynchronously");
2055 RequestNotificationStatus status = RequestNotificationStatus.Continue;
2056 HttpContext context = (HttpContext) ar.AsyncState;
2057 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
2060 context.ApplicationInstance.EndProcessRequestNotification(ar);
2062 catch (Exception e) {
2063 status = RequestNotificationStatus.FinishRequest;
2064 context.AddError(e);
2067 // RequestContext is set to null if this is the last notification, so we need to save it
2068 // for the call to PostCompletion
2069 IntPtr requestContext = wr.RequestContext;
2071 FinishRequestNotification(wr, context, ref status);
2073 // set the notification context to null since we are exiting this notification
2074 context.NotificationContext = null;
2076 // Indicate completion to IIS, so that it can resume
2077 // request processing on an IIS thread
2078 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion(" + status + ")");
2079 int result = UnsafeIISMethods.MgdPostCompletion(requestContext, status);
2080 Misc.ThrowIfFailedHr(result);
2084 * Async completion of managed pipeline (called at most one time).
2086 private void OnHandlerCompletion(IAsyncResult ar) {
2087 HttpContext context = (HttpContext)ar.AsyncState;
2090 context.AsyncAppHandler.EndProcessRequest(ar);
2092 catch (Exception e) {
2093 context.AddError(e);
2096 // no longer keep AsyncAppHandler poiting to the application
2097 // is only needed to call EndProcessRequest
2098 context.AsyncAppHandler = null;
2101 FinishRequest(context.WorkerRequest, context, context.Error);
2105 * Notification from worker request that it is done writing from buffer
2106 * so that the buffers can be recycled
2108 private void EndOfSendCallback(HttpWorkerRequest wr, Object arg) {
2109 Debug.Trace("PipelineRuntime", "HttpRuntime.EndOfSendCallback");
2110 HttpContext context = (HttpContext)arg;
2111 context.Request.Dispose();
2112 context.Response.Dispose();
2116 * Notification when something in the bin directory changed
2118 private void OnCriticalDirectoryChange(Object sender, FileChangeEvent e) {
2119 // shutdown the app domain
2120 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of bin dir change or directory rename." +
2121 " FileName=" + e.FileName + " Action=" + e.Action);
2123 ApplicationShutdownReason reason = ApplicationShutdownReason.None;
2124 string directoryName = new DirectoryInfo(e.FileName).Name;
2126 string message = FileChangesMonitor.GenerateErrorMessage(e.Action);
2127 message = (message != null) ? message + directoryName : directoryName + " dir change or directory rename";
2129 if (StringUtil.EqualsIgnoreCase(directoryName, CodeDirectoryName)) {
2130 reason = ApplicationShutdownReason.CodeDirChangeOrDirectoryRename;
2132 else if (StringUtil.EqualsIgnoreCase(directoryName, ResourcesDirectoryName)) {
2133 reason = ApplicationShutdownReason.ResourcesDirChangeOrDirectoryRename;
2135 else if (StringUtil.EqualsIgnoreCase(directoryName, BrowsersDirectoryName)) {
2136 reason = ApplicationShutdownReason.BrowsersDirChangeOrDirectoryRename;
2138 else if (StringUtil.EqualsIgnoreCase(directoryName, BinDirectoryName)) {
2139 reason = ApplicationShutdownReason.BinDirChangeOrDirectoryRename;
2142 if (e.Action == FileAction.Added) {
2143 // Make sure HttpRuntime does not ignore the appdomain shutdown if a file is added (VSWhidbey 363481)
2144 HttpRuntime.SetUserForcedShutdown();
2146 Debug.Trace("AppDomainFactorySpecial", "Call SetUserForcedShutdown: FileName=" + e.FileName + "; now=" + DateTime.Now);
2149 ShutdownAppDomain(reason, message);
2153 * Coalesce file change notifications to minimize sharing violations and AppDomain restarts (ASURT 147492)
2155 internal static void CoalesceNotifications() {
2156 int waitChangeNotification = HttpRuntimeSection.DefaultWaitChangeNotification;
2157 int maxWaitChangeNotification = HttpRuntimeSection.DefaultMaxWaitChangeNotification;
2159 HttpRuntimeSection config = RuntimeConfig.GetAppLKGConfig().HttpRuntime;
2160 if (config != null) {
2161 waitChangeNotification = config.WaitChangeNotification;
2162 maxWaitChangeNotification = config.MaxWaitChangeNotification;
2168 if (waitChangeNotification == 0 || maxWaitChangeNotification == 0)
2171 DateTime maxWait = DateTime.UtcNow.AddSeconds(maxWaitChangeNotification);
2172 // Coalesce file change notifications
2174 while (DateTime.UtcNow < maxWait) {
2175 if (DateTime.UtcNow > _theRuntime.LastShutdownAttemptTime.AddSeconds(waitChangeNotification))
2185 // appdomain shutdown eventhandler
2186 internal static event BuildManagerHostUnloadEventHandler AppDomainShutdown;
2188 internal static void OnAppDomainShutdown(BuildManagerHostUnloadEventArgs e) {
2189 if (AppDomainShutdown != null) {
2190 AppDomainShutdown(_theRuntime, e);
2194 internal static void SetUserForcedShutdown() {
2195 _theRuntime._userForcedShutdown = true;
2199 * Shutdown the current app domain
2201 internal static bool ShutdownAppDomain(ApplicationShutdownReason reason, string message) {
2202 return ShutdownAppDomainWithStackTrace(reason, message, null /*stackTrace*/);
2206 * Shutdown the current app domain with a stack trace. This is useful for callers that are running
2207 * on a QUWI callback, and wouldn't provide a meaningful stack trace by default.
2209 internal static bool ShutdownAppDomainWithStackTrace(ApplicationShutdownReason reason, string message, string stackTrace) {
2210 SetShutdownReason(reason, message);
2211 return ShutdownAppDomain(stackTrace);
2214 private static bool ShutdownAppDomain(string stackTrace) {
2216 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
2217 "*** ShutdownAppDomain " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
2218 + ": _appDomainAppId=" + HttpRuntime.AppDomainAppId);
2220 // Ignore notifications during the processing of the first request (ASURT 100335)
2221 // skip this if LastShutdownAttemptTime has been set
2222 if (_theRuntime.LastShutdownAttemptTime == DateTime.MinValue && !_theRuntime._firstRequestCompleted && !_theRuntime._userForcedShutdown) {
2223 // check the timeout (don't disable notifications forever
2224 int delayTimeoutSec = HttpRuntimeSection.DefaultDelayNotificationTimeout;
2227 RuntimeConfig runtimeConfig = RuntimeConfig.GetAppLKGConfig();
2228 if (runtimeConfig != null) {
2229 HttpRuntimeSection runtimeSection = runtimeConfig.HttpRuntime;
2230 if (runtimeSection != null) {
2231 delayTimeoutSec = (int)runtimeSection.DelayNotificationTimeout.TotalSeconds;
2233 if (DateTime.UtcNow < _theRuntime._firstRequestStartTime.AddSeconds(delayTimeoutSec)) {
2234 Debug.Trace("AppDomainFactory", "ShutdownAppDomain IGNORED (1st request is not done yet), Id = " + AppDomainAppId);
2245 _theRuntime.RaiseShutdownWebEventOnce();
2248 // VSWhidbey 444472: if an exception is thrown, we consume it and continue executing the following code.
2251 // Update last time ShutdownAppDomain was called
2252 _theRuntime.LastShutdownAttemptTime = DateTime.UtcNow;
2254 if (!HostingEnvironment.ShutdownInitiated) {
2255 // This shutdown is not triggered by hosting environment - let it do the job
2256 HostingEnvironment.InitiateShutdownWithoutDemand();
2260 //WOS 1400290: CantUnloadAppDomainException in ISAPI mode, wait until HostingEnvironment.ShutdownThisAppDomainOnce completes
2261 if (HostingEnvironment.ShutdownInProgress) {
2265 // Make sure we don't go through shutdown logic many times
2266 if (!_theRuntime.InitiateShutdownOnce())
2269 Debug.Trace("AppDomainFactory", "ShutdownAppDomain, Id = " + AppDomainAppId + ", ShutdownInProgress=" + ShutdownInProgress
2270 + ", ShutdownMessage=" + _theRuntime._shutDownMessage);
2272 if (String.IsNullOrEmpty(stackTrace) && !BuildManagerHost.InClientBuildManager) {
2273 // Avoid calling Environment.StackTrace if we are in the ClientBuildManager (Dev10
2275 // Instrument to be able to see what's causing a shutdown
2276 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
2278 _theRuntime._shutDownStack = Environment.StackTrace;
2281 CodeAccessPermission.RevertAssert();
2285 _theRuntime._shutDownStack = stackTrace;
2288 // Notify when appdomain is about to shutdown.
2289 OnAppDomainShutdown(new BuildManagerHostUnloadEventArgs(_theRuntime._shutdownReason));
2291 // unload app domain from another CLR thread
2292 ThreadPool.QueueUserWorkItem(_theRuntime._appDomainUnloadallback);
2297 internal static void RecoverFromUnexceptedAppDomainUnload() {
2298 if (_theRuntime._shutdownInProgress)
2301 // someone unloaded app domain directly - tell unmanaged code
2302 Debug.Trace("AppDomainFactory", "Unexpected AppDomainUnload");
2303 _theRuntime._shutdownInProgress = true;
2305 // tell unmanaged code not to dispatch requests to this app domain
2307 ISAPIRuntime.RemoveThisAppDomainFromUnmanagedTable();
2308 PipelineRuntime.RemoveThisAppDomainFromUnmanagedTable();
2309 AddAppDomainTraceMessage("AppDomainRestart");
2312 // release all resources
2313 _theRuntime.Dispose();
2318 * Notification when app-level Config changed
2320 internal static void OnConfigChange(String message) {
2321 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of config change");
2322 ShutdownAppDomain(ApplicationShutdownReason.ConfigurationChange, (message != null) ? message : "CONFIG change");
2325 // Intrumentation to remember the overwhelming file change
2326 internal static void SetShutdownReason(ApplicationShutdownReason reason, String message) {
2327 if (_theRuntime._shutdownReason == ApplicationShutdownReason.None) {
2328 _theRuntime._shutdownReason = reason;
2331 SetShutdownMessage(message);
2334 internal static void SetShutdownMessage(String message) {
2335 if (message != null) {
2336 if (_theRuntime._shutDownMessage == null)
2337 _theRuntime._shutDownMessage = message;
2339 _theRuntime._shutDownMessage += "\r\n" + message;
2344 // public method is on HostingEnvironment
2345 internal static ApplicationShutdownReason ShutdownReason {
2346 get { return _theRuntime._shutdownReason; }
2350 // public static APIs
2354 * Process one request
2358 /// <para><SPAN>The method that drives
2359 /// all ASP.NET web processing execution.</SPAN></para>
2361 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
2362 public static void ProcessRequest(HttpWorkerRequest wr) {
2364 throw new ArgumentNullException("wr");
2366 if (HttpRuntime.UseIntegratedPipeline) {
2367 throw new PlatformNotSupportedException(SR.GetString(SR.Method_Not_Supported_By_Iis_Integrated_Mode, "HttpRuntime.ProcessRequest"));
2370 ProcessRequestNoDemand(wr);
2374 internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) {
2375 RequestQueue rq = _theRuntime._requestQueue;
2377 wr.UpdateInitialCounters();
2379 if (rq != null) // could be null before first request
2380 wr = rq.GetRequestToExecute(wr);
2383 CalculateWaitTimeAndUpdatePerfCounter(wr);
2384 wr.ResetStartTime();
2385 ProcessRequestNow(wr);
2390 private static void CalculateWaitTimeAndUpdatePerfCounter(HttpWorkerRequest wr) {
2391 DateTime begin = wr.GetStartTime();
2393 TimeSpan elapsed = DateTime.UtcNow.Subtract(begin);
2394 long milli = elapsed.Ticks / TimeSpan.TicksPerMillisecond;
2396 if (milli > Int32.MaxValue)
2397 milli = Int32.MaxValue;
2399 PerfCounters.SetGlobalCounter(GlobalPerfCounter.REQUEST_WAIT_TIME, (int)milli);
2400 PerfCounters.SetCounter(AppPerfCounter.APP_REQUEST_WAIT_TIME, (int)milli);
2403 internal static void ProcessRequestNow(HttpWorkerRequest wr) {
2404 _theRuntime.ProcessRequestInternal(wr);
2407 internal static void RejectRequestNow(HttpWorkerRequest wr, bool silent) {
2408 _theRuntime.RejectRequestInternal(wr, silent);
2413 /// <para>Removes all items from the cache and shuts down the runtime.</para>
2415 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
2416 public static void Close() {
2417 Debug.Trace("AppDomainFactory", "HttpRuntime.Close, ShutdownInProgress=" + ShutdownInProgress);
2418 if (_theRuntime.InitiateShutdownOnce()) {
2419 SetShutdownReason(ApplicationShutdownReason.HttpRuntimeClose, "HttpRuntime.Close is called");
2421 if (HostingEnvironment.IsHosted) {
2422 // go throw initiate shutdown for hosted scenarios
2423 HostingEnvironment.InitiateShutdownWithoutDemand();
2426 _theRuntime.Dispose();
2433 /// <para>Unloads the current app domain.</para>
2435 public static void UnloadAppDomain() {
2436 _theRuntime._userForcedShutdown = true;
2437 ShutdownAppDomain(ApplicationShutdownReason.UnloadAppDomainCalled, "User code called UnloadAppDomain");
2440 private DateTime LastShutdownAttemptTime {
2444 dt = _lastShutdownAttemptTime;
2450 _lastShutdownAttemptTime = value;
2455 internal static Profiler Profile {
2457 return _theRuntime._profiler;
2461 internal static bool IsTrustLevelInitialized {
2463 return !HostingEnvironment.IsHosted || TrustLevel != null;
2467 internal static NamedPermissionSet NamedPermissionSet {
2469 // Make sure we have already initialized the trust level
2473 return _theRuntime._namedPermissionSet;
2477 internal static PolicyLevel PolicyLevel {
2479 return _theRuntime._policyLevel;
2483 internal static string HostSecurityPolicyResolverType {
2485 return _theRuntime._hostSecurityPolicyResolverType;
2489 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Unrestricted)]
2490 public static NamedPermissionSet GetNamedPermissionSet() {
2491 NamedPermissionSet namedPermissionSet = _theRuntime._namedPermissionSet;
2492 if (namedPermissionSet == null) {
2496 return new NamedPermissionSet(namedPermissionSet);
2500 internal static bool IsFullTrust {
2502 // Make sure we have already initialized the trust level
2503 Debug.Assert(IsTrustLevelInitialized);
2505 return (_theRuntime._namedPermissionSet == null);
2510 * Check that the current trust level allows access to a virtual path. Throw if it doesn't,
2512 internal static void CheckVirtualFilePermission(string virtualPath) {
2513 string physicalPath = HostingEnvironment.MapPath(virtualPath);
2514 CheckFilePermission(physicalPath);
2518 * Check that the current trust level allows access to a path. Throw if it doesn't,
2520 internal static void CheckFilePermission(string path) {
2521 CheckFilePermission(path, false);
2524 internal static void CheckFilePermission(string path, bool writePermissions) {
2525 if (!HasFilePermission(path, writePermissions)) {
2526 throw new HttpException(SR.GetString(SR.Access_denied_to_path, GetSafePath(path)));
2530 internal static bool HasFilePermission(string path) {
2531 return HasFilePermission(path, false);
2534 internal static bool HasFilePermission(string path, bool writePermissions) {
2535 // WOS #1523618: need to skip this check for HttpResponse.ReportRuntimeError when reporting an
2536 // InitializationException (e.g., necessary to display line info for ConfigurationException).
2538 if (TrustLevel == null && InitializationException != null) {
2542 // Make sure we have already initialized the trust level
2543 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted, "TrustLevel != null || !HostingEnvironment.IsHosted");
2545 // If we don't have a NamedPermissionSet, we're in full trust
2546 if (NamedPermissionSet == null)
2549 bool fAccess = false;
2551 // Check that the user has permission to the path
2552 IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(FileIOPermission));
2553 if (allowedPermission != null) {
2554 IPermission askedPermission = null;
2556 if (!writePermissions)
2557 askedPermission = new FileIOPermission(FileIOPermissionAccess.Read, path);
2559 askedPermission = new FileIOPermission(FileIOPermissionAccess.AllAccess, path);
2562 // This could happen if the path is not absolute
2565 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2571 internal static bool HasWebPermission(Uri uri) {
2573 // Make sure we have already initialized the trust level
2574 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2576 // If we don't have a NamedPermissionSet, we're in full trust
2577 if (NamedPermissionSet == null)
2580 bool fAccess = false;
2582 // Check that the user has permission to the URI
2583 IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(WebPermission));
2584 if (allowedPermission != null) {
2585 IPermission askedPermission = null;
2587 askedPermission = new WebPermission(NetworkAccess.Connect, uri.ToString());
2592 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2598 internal static bool HasDbPermission(DbProviderFactory factory) {
2600 // Make sure we have already initialized the trust level
2601 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2603 // If we don't have a NamedPermissionSet, we're in full trust
2604 if (NamedPermissionSet == null)
2607 bool fAccess = false;
2609 // Check that the user has permission to the provider
2610 CodeAccessPermission askedPermission = factory.CreatePermission(PermissionState.Unrestricted);
2611 if (askedPermission != null) {
2612 IPermission allowedPermission = NamedPermissionSet.GetPermission(askedPermission.GetType());
2613 if (allowedPermission != null) {
2614 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2621 internal static bool HasPathDiscoveryPermission(string path) {
2622 // WOS #1523618: need to skip this check for HttpResponse.ReportRuntimeError when reporting an
2623 // InitializationException (e.g., necessary to display line info for ConfigurationException).
2625 if (TrustLevel == null && InitializationException != null) {
2629 // Make sure we have already initialized the trust level
2630 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2632 // If we don't have a NamedPermissionSet, we're in full trust
2633 if (NamedPermissionSet == null)
2636 bool fAccess = false;
2638 // Check that the user has permission to the path
2639 IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(FileIOPermission));
2640 if (allowedPermission != null) {
2641 IPermission askedPermission = new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path);
2642 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2649 internal static bool HasAppPathDiscoveryPermission() {
2650 return HasPathDiscoveryPermission(HttpRuntime.AppDomainAppPathInternal);
2653 internal static string GetSafePath(string path) {
2654 if (String.IsNullOrEmpty(path))
2658 if (HasPathDiscoveryPermission(path)) // could throw on bad filenames
2664 return Path.GetFileName(path);
2668 * Check that the current trust level allows Unmanaged access
2670 internal static bool HasUnmanagedPermission() {
2672 // Make sure we have already initialized the trust level
2673 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2675 // If we don't have a NamedPermissionSet, we're in full trust
2676 if (NamedPermissionSet == null)
2679 SecurityPermission securityPermission = (SecurityPermission)NamedPermissionSet.GetPermission(
2680 typeof(SecurityPermission));
2681 if (securityPermission == null)
2684 return (securityPermission.Flags & SecurityPermissionFlag.UnmanagedCode) != 0;
2687 internal static bool HasAspNetHostingPermission(AspNetHostingPermissionLevel level) {
2689 // Make sure we have already initialized the trust level
2694 // If we don't have a NamedPermissionSet, we're in full trust
2695 if (NamedPermissionSet == null)
2698 AspNetHostingPermission permission = (AspNetHostingPermission)NamedPermissionSet.GetPermission(
2699 typeof(AspNetHostingPermission));
2700 if (permission == null)
2703 return (permission.Level >= level);
2706 internal static void CheckAspNetHostingPermission(AspNetHostingPermissionLevel level, String errorMessageId) {
2707 if (!HasAspNetHostingPermission(level)) {
2708 throw new HttpException(SR.GetString(errorMessageId));
2712 // If we're not in full trust, fail if the passed in type doesn't have the APTCA bit
2713 internal static void FailIfNoAPTCABit(Type t, ElementInformation elemInfo, string propertyName) {
2715 if (!IsTypeAllowedInConfig(t)) {
2716 if (null != elemInfo) {
2717 PropertyInformation propInfo = elemInfo.Properties[propertyName];
2719 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName),
2720 propInfo.Source, propInfo.LineNumber);
2723 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName));
2728 // If we're not in full trust, fail if the passed in type doesn't have the APTCA bit
2729 internal static void FailIfNoAPTCABit(Type t, XmlNode node) {
2731 if (!IsTypeAllowedInConfig(t)) {
2732 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName),
2737 private static bool HasAPTCABit(Assembly assembly) {
2738 return assembly.IsDefined(typeof(AllowPartiallyTrustedCallersAttribute), inherit: false);
2741 // Check if the type is allowed to be used in config by checking the APTCA bit
2742 internal static bool IsTypeAllowedInConfig(Type t) {
2744 // Allow everything in full trust
2745 if (HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted))
2748 return IsTypeAccessibleFromPartialTrust(t);
2751 internal static bool IsTypeAccessibleFromPartialTrust(Type t) {
2752 Assembly assembly = t.Assembly;
2754 if (assembly.SecurityRuleSet == SecurityRuleSet.Level1) {
2755 // Level 1 CAS uses transparency as an auditing mechanism rather than an enforcement mechanism, so we can't
2756 // perform a transparency check. Instead, allow the call to go through if:
2757 // (a) the referenced assembly is partially trusted, hence it cannot do anything dangerous; or
2758 // (b) the assembly is fully trusted and has APTCA.
2759 return (!assembly.IsFullyTrusted || HasAPTCABit(assembly));
2763 // Some GACed assemblies register critical modules / handlers. We can't break these scenarios for .NET 4.5, but we should
2764 // remove this APTCA check when we fix DevDiv #85358 and use only the transparency check defined below.
2765 if (HasAPTCABit(assembly)) {
2768 // ** END TEMPORARY **
2770 // Level 2 CAS uses transparency as an enforcement mechanism, so we can perform a transparency check.
2771 // Transparent and SafeCritical types are safe to use from partial trust code.
2772 return (t.IsSecurityTransparent || t.IsSecuritySafeCritical);
2776 internal static FileChangesMonitor FileChangesMonitor {
2777 get { return _theRuntime._fcm; }
2780 internal static RequestTimeoutManager RequestTimeoutManager {
2781 get { return _theRuntime._timeoutManager; }
2786 /// <para>Provides access to the cache.</para>
2788 public static Cache Cache {
2791 if (HttpRuntime.AspInstallDirectoryInternal == null) {
2792 throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2795 // In a web app, ReadCacheInternalConfig() is called from HttpRuntime.HostingInit.
2796 // However, if the cache is used by a non-http app, HttpRuntime.HostingInit won't
2797 // be called and we need to find a way to call ReadCacheInternalConfig().
2798 // The safe and inexpensive place to call it is when the non-http app accesses the
2799 // Cache thru HttpRuntime.Cache.
2801 // ReadCacheInternalConfig() protects itself from being read multiple times.
2803 Cache cachePublic = _theRuntime._cachePublic;
2804 if (cachePublic == null) {
2805 CacheInternal cacheInternal = CacheInternal;
2806 CacheSection cacheSection = RuntimeConfig.GetAppConfig().Cache;
2807 cacheInternal.ReadCacheInternalConfig(cacheSection);
2808 _theRuntime._cachePublic = cacheInternal.CachePublic;
2809 cachePublic = _theRuntime._cachePublic;
2816 private void CreateCache() {
2818 if (_cacheInternal == null) {
2819 _cacheInternal = CacheInternal.Create();
2824 internal static CacheInternal GetCacheInternal(bool createIfDoesNotExist) {
2825 // Note that we only create the cache on first access,
2826 // not in HttpRuntime initialization.
2827 // This prevents cache timers from running when
2828 // the cache is not used.
2829 CacheInternal cacheInternal = _theRuntime._cacheInternal;
2830 if (cacheInternal == null && createIfDoesNotExist) {
2831 _theRuntime.CreateCache();
2832 cacheInternal = _theRuntime._cacheInternal;
2835 return cacheInternal;
2838 internal static CacheInternal CacheInternal {
2839 get { return GetCacheInternal(createIfDoesNotExist: true); }
2843 /// <para>[To be supplied.]</para>
2845 public static string AspInstallDirectory {
2847 String path = AspInstallDirectoryInternal;
2850 throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2853 InternalSecurityPermissions.PathDiscovery(path).Demand();
2858 internal static string AspInstallDirectoryInternal {
2859 get { return s_installDirectory; }
2863 // Return the client script virtual path, e.g. "/aspnet_client/system_web/2_0_50217"
2865 public static string AspClientScriptVirtualPath {
2867 if (_theRuntime._clientScriptVirtualPath == null) {
2868 string aspNetVersion = VersionInfo.SystemWebVersion;
2869 string clientScriptVirtualPath = AspNetClientFilesParentVirtualPath + aspNetVersion.Substring(0, aspNetVersion.LastIndexOf('.')).Replace('.', '_');
2871 _theRuntime._clientScriptVirtualPath = clientScriptVirtualPath;
2874 return _theRuntime._clientScriptVirtualPath;
2878 public static string AspClientScriptPhysicalPath {
2880 String path = AspClientScriptPhysicalPathInternal;
2883 throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2891 // Return the client script physical path, e.g. @"c:\windows\microsoft.net\framework\v2.0.50217.0\asp.netclientfiles"
2893 internal static string AspClientScriptPhysicalPathInternal {
2895 if (_theRuntime._clientScriptPhysicalPath == null) {
2896 string clientScriptPhysicalPath = System.IO.Path.Combine(AspInstallDirectoryInternal, AspNetClientFilesSubDirectory);
2898 _theRuntime._clientScriptPhysicalPath = clientScriptPhysicalPath;
2901 return _theRuntime._clientScriptPhysicalPath;
2907 /// <para>[To be supplied.]</para>
2909 public static string ClrInstallDirectory {
2911 String path = ClrInstallDirectoryInternal;
2912 InternalSecurityPermissions.PathDiscovery(path).Demand();
2917 internal static string ClrInstallDirectoryInternal {
2918 get { return HttpConfigurationSystem.MsCorLibDirectory; }
2924 /// <para>[To be supplied.]</para>
2926 public static string MachineConfigurationDirectory {
2928 String path = MachineConfigurationDirectoryInternal;
2929 InternalSecurityPermissions.PathDiscovery(path).Demand();
2934 internal static string MachineConfigurationDirectoryInternal {
2935 get { return HttpConfigurationSystem.MachineConfigurationDirectory; }
2938 internal static bool IsEngineLoaded {
2939 get { return s_isEngineLoaded; }
2944 // Static app domain related properties
2949 /// <para>[To be supplied.]</para>
2951 public static String CodegenDir {
2953 String path = CodegenDirInternal;
2954 InternalSecurityPermissions.PathDiscovery(path).Demand();
2959 internal static string CodegenDirInternal {
2960 get { return _theRuntime._codegenDir; }
2963 internal static string TempDirInternal {
2964 get { return _theRuntime._tempDir; }
2969 /// <para>[To be supplied.]</para>
2971 public static String AppDomainAppId {
2973 return _theRuntime._appDomainAppId;
2977 internal static bool IsAspNetAppDomain {
2978 get { return AppDomainAppId != null; }
2984 /// <para>[To be supplied.]</para>
2986 public static String AppDomainAppPath {
2988 InternalSecurityPermissions.AppPathDiscovery.Demand();
2989 return AppDomainAppPathInternal;
2993 internal static string AppDomainAppPathInternal {
2994 get { return _theRuntime._appDomainAppPath; }
2999 /// <para>[To be supplied.]</para>
3001 public static String AppDomainAppVirtualPath {
3003 return VirtualPath.GetVirtualPathStringNoTrailingSlash(_theRuntime._appDomainAppVPath);
3007 // Save as AppDomainAppVirtualPath, but includes the trailng slash. We can't change
3008 // AppDomainAppVirtualPath since it's public.
3009 internal static String AppDomainAppVirtualPathString {
3011 return VirtualPath.GetVirtualPathString(_theRuntime._appDomainAppVPath);
3015 internal static VirtualPath AppDomainAppVirtualPathObject {
3017 return _theRuntime._appDomainAppVPath;
3021 internal static bool IsPathWithinAppRoot(String path) {
3022 if (AppDomainIdInternal == null)
3023 return true; // app domain not initialized
3025 return UrlPath.IsEqualOrSubpath(AppDomainAppVirtualPathString, path);
3030 /// <para>[To be supplied.]</para>
3032 public static String AppDomainId {
3033 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
3035 return AppDomainIdInternal;
3039 internal static string AppDomainIdInternal {
3040 get { return _theRuntime._appDomainId; }
3046 /// <para>[To be supplied.]</para>
3048 public static String BinDirectory {
3050 String path = BinDirectoryInternal;
3051 InternalSecurityPermissions.PathDiscovery(path).Demand();
3056 internal static string BinDirectoryInternal {
3057 get { return Path.Combine(_theRuntime._appDomainAppPath, BinDirectoryName) + Path.DirectorySeparatorChar; }
3061 internal static VirtualPath CodeDirectoryVirtualPath {
3062 get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(CodeDirectoryName); }
3065 internal static VirtualPath ResourcesDirectoryVirtualPath {
3066 get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(ResourcesDirectoryName); }
3069 internal static VirtualPath WebRefDirectoryVirtualPath {
3070 get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(WebRefDirectoryName); }
3075 /// <para>[To be supplied.]</para>
3077 public static bool IsOnUNCShare {
3078 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
3080 return IsOnUNCShareInternal;
3084 internal static bool IsOnUNCShareInternal {
3085 get { return _theRuntime._isOnUNCShare; }
3090 // Static helper to retrieve app domain values
3093 private static String GetAppDomainString(String key) {
3094 Object x = Thread.GetDomain().GetData(key);
3099 internal static void AddAppDomainTraceMessage(String message) {
3100 const String appDomainTraceKey = "ASP.NET Domain Trace";
3101 AppDomain d = Thread.GetDomain();
3102 String m = d.GetData(appDomainTraceKey) as String;
3103 d.SetData(appDomainTraceKey, (m != null) ? m + " ... " + message : message);
3106 // Gets the version of the ASP.NET framework the current web applications is targeting.
3107 // This property is normally set via the <httpRuntime> element's "targetFramework"
3108 // attribute. The property is not guaranteed to return a correct value if the current
3109 // AppDomain is not an ASP.NET web application AppDomain.
3110 public static Version TargetFramework {
3112 return BinaryCompatibility.Current.TargetFramework;
3121 internal static bool DebuggingEnabled {
3122 get { return _theRuntime._debuggingEnabled; }
3125 internal static bool ConfigInited {
3126 get { return _theRuntime._configInited; }
3129 internal static bool FusionInited {
3130 get { return _theRuntime._fusionInited; }
3133 internal static bool ApartmentThreading {
3134 get { return _theRuntime._apartmentThreading; }
3137 internal static bool ShutdownInProgress {
3138 get { return _theRuntime._shutdownInProgress; }
3141 internal static string TrustLevel {
3142 get { return _theRuntime._trustLevel; }
3145 internal static string WpUserId {
3146 get { return _theRuntime._wpUserId; }
3150 private void SetTrustLevel(TrustSection trustSection, SecurityPolicySection securityPolicySection) {
3151 // Use a temporary variable, since we use the field as a signal that the trust has really
3152 // been set, which is not the case until later in this method.
3153 string trustLevel = trustSection.Level;
3155 if (trustSection.Level == "Full") {
3156 _trustLevel = trustLevel;
3160 if (securityPolicySection == null || securityPolicySection.TrustLevels[trustSection.Level] == null) {
3161 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level), String.Empty, 0);
3162 // Do not give out configuration information since we don't know what trust level we are
3163 // supposed to be running at. If the information below is added to the error it might expose
3164 // part of the config file that the users does not have permissions to see. VS261145
3165 // ,trustSection.ElementInformation.Properties["level"].Source,
3166 // trustSection.ElementInformation.Properties["level"].LineNumber);
3169 if (trustSection.Level == "Minimal" || trustSection.Level == "Low" ||
3170 trustSection.Level == "Medium" || trustSection.Level == "High") {
3171 file = (String)securityPolicySection.TrustLevels[trustSection.Level].LegacyPolicyFileExpanded;
3174 file = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
3176 if (file == null || !FileUtil.FileExists(file)) {
3177 //if HttpContext.Current.IsCustomErrorEnabled
3178 throw new HttpException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
3180 // throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level),
3181 // trustSection.Filename, trustSection.LineNumber);
3184 bool foundGacToken = false;
3185 #pragma warning disable 618
3186 PolicyLevel policyLevel = CreatePolicyLevel(file, AppDomainAppPathInternal, CodegenDirInternal, trustSection.OriginUrl, out foundGacToken);
3188 // see if the policy file contained a v1.x UrlMembershipCondition containing
3189 // a GAC token. If so, let's upgrade it by adding a code group granting
3190 // full trust to code from the GAC
3191 if (foundGacToken) {
3192 // walk the code groups at the app domain level and look for one that grants
3193 // access to the GAC with an UrlMembershipCondition.
3194 CodeGroup rootGroup = policyLevel.RootCodeGroup;
3195 bool foundGacCondition = false;
3196 foreach (CodeGroup childGroup in rootGroup.Children) {
3197 if (childGroup.MembershipCondition is GacMembershipCondition) {
3198 foundGacCondition = true;
3200 // if we found the GAC token and also have the GacMembershipCondition
3201 // the policy file needs to be upgraded to just include the GacMembershipCondition
3202 Debug.Assert(!foundGacCondition);
3207 // add one as a child of the toplevel group after
3208 // some sanity checking to make sure it's an ASP.NET policy file
3209 // which always begins with a FirstMatchCodeGroup granting nothing
3210 // this might not upgrade some custom policy files
3211 if (!foundGacCondition) {
3212 if (rootGroup is FirstMatchCodeGroup) {
3213 FirstMatchCodeGroup firstMatch = (FirstMatchCodeGroup)rootGroup;
3214 if (firstMatch.MembershipCondition is AllMembershipCondition &&
3215 firstMatch.PermissionSetName == "Nothing") {
3216 PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
3218 CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(),
3219 new PolicyStatement(fullTrust));
3222 // now, walk the current groups and insert our new group
3223 // immediately before the old Gac group
3224 // we'll need to use heuristics for this:
3225 // it will be an UrlMembershipCondition group with full trust
3226 CodeGroup newRoot = new FirstMatchCodeGroup(rootGroup.MembershipCondition, rootGroup.PolicyStatement);
3227 foreach (CodeGroup childGroup in rootGroup.Children) {
3229 // is this the target old $Gac$ group?
3230 // insert our new GacMembershipCondition group ahead of it
3231 if ((childGroup is UnionCodeGroup) &&
3232 (childGroup.MembershipCondition is UrlMembershipCondition) &&
3233 childGroup.PolicyStatement.PermissionSet.IsUnrestricted()) {
3234 if (null != gacGroup) {
3235 newRoot.AddChild(gacGroup);
3240 // append this group to the root group
3241 // AddChild itself does a deep Copy to get any
3242 // child groups so we don't need one here
3243 newRoot.AddChild(childGroup);
3246 policyLevel.RootCodeGroup = newRoot;
3247 //Debug.Trace("internal", "PolicyLevel: " + policyLevel.ToXml());
3251 #pragma warning restore 618
3255 #pragma warning disable 618
3256 AppDomain.CurrentDomain.SetAppDomainPolicy(policyLevel);
3257 _namedPermissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
3258 #pragma warning restore 618
3260 _trustLevel = trustLevel;
3262 _fcm.StartMonitoringFile(file, new FileChangeEventHandler(this.OnSecurityPolicyFileChange));
3265 #pragma warning disable 618
3266 private static PolicyLevel CreatePolicyLevel(String configFile, String appDir, String binDir, String strOriginUrl, out bool foundGacToken) {
3267 // Read in the config file to a string.
3268 FileStream file = new FileStream(configFile, FileMode.Open, FileAccess.Read);
3269 StreamReader reader = new StreamReader(file, Encoding.UTF8);
3270 String strFileData = reader.ReadToEnd();
3274 appDir = FileUtil.RemoveTrailingDirectoryBackSlash(appDir);
3275 binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir);
3277 strFileData = strFileData.Replace("$AppDir$", appDir);
3278 strFileData = strFileData.Replace("$AppDirUrl$", MakeFileUrl(appDir));
3279 strFileData = strFileData.Replace("$CodeGen$", MakeFileUrl(binDir));
3280 if (strOriginUrl == null)
3281 strOriginUrl = String.Empty;
3282 strFileData = strFileData.Replace("$OriginHost$", strOriginUrl);
3284 // see if the file contains a GAC token
3285 // if so, do the replacement and record the
3286 // fact so that we later add a GacMembershipCondition
3287 // codegroup to the PolicyLevel
3288 int ndx = strFileData.IndexOf("$Gac$", StringComparison.Ordinal);
3290 string gacLocation = GetGacLocation();
3291 if (gacLocation != null)
3292 gacLocation = MakeFileUrl(gacLocation);
3293 if (gacLocation == null)
3294 gacLocation = String.Empty;
3296 strFileData = strFileData.Replace("$Gac$", gacLocation);
3297 foundGacToken = true;
3300 foundGacToken = false;
3303 return SecurityManager.LoadPolicyLevelFromString(strFileData, PolicyLevelType.AppDomain);
3305 #pragma warning restore 618
3307 private void SetTrustParameters(TrustSection trustSection, SecurityPolicySection securityPolicySection, PolicyLevel policyLevel) {
3308 _trustLevel = trustSection.Level;
3309 if (_trustLevel != "Full") {
3310 // if we are in partial trust, HostingEnvironment should init HttpRuntime with a non-null PolicyLevel object
3311 Debug.Assert(policyLevel != null);
3313 _namedPermissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
3314 _policyLevel = policyLevel;
3315 _hostSecurityPolicyResolverType = trustSection.HostSecurityPolicyResolverType;
3316 String file = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
3317 _fcm.StartMonitoringFile(file, new FileChangeEventHandler(this.OnSecurityPolicyFileChange));
3322 * Notification when something in the code-access security policy file changed
3324 private void OnSecurityPolicyFileChange(Object sender, FileChangeEvent e) {
3325 // shutdown the app domain
3326 Debug.Trace("AppDomainFactory", "Shutting down appdomain because code-access security policy file changed");
3327 string message = FileChangesMonitor.GenerateErrorMessage(e.Action, e.FileName);
3328 if (message == null) {
3329 message = "Change in code-access security policy file";
3331 ShutdownAppDomain(ApplicationShutdownReason.ChangeInSecurityPolicyFile,
3336 // notification when app_offline.htm file changed or created
3337 private void OnAppOfflineFileChange(Object sender, FileChangeEvent e) {
3338 // shutdown the app domain
3339 Debug.Trace("AppOffline", AppOfflineFileName + " changed - shutting down the app domain");
3340 Debug.Trace("AppDomainFactory", "Shutting down appdomain because " + AppOfflineFileName + " file changed");
3341 // WOS 1948399: set _userForcedShutdown to avoid DelayNotificationTimeout, since first request has not completed yet in integrated mode;
3342 SetUserForcedShutdown();
3343 string message = FileChangesMonitor.GenerateErrorMessage(e.Action, AppOfflineFileName);
3344 if (message == null) {
3345 message = "Change in " + AppOfflineFileName;
3347 ShutdownAppDomain(ApplicationShutdownReason.ConfigurationChange, message);
3350 internal static String MakeFileUrl(String path) {
3351 Uri uri = new Uri(path);
3352 return uri.ToString();
3355 internal static String GetGacLocation() {
3357 StringBuilder buf = new StringBuilder(262);
3362 if (UnsafeNativeMethods.GetCachePath(2, buf, ref iSize) >= 0)
3363 return buf.ToString();
3364 throw new HttpException(SR.GetString(SR.GetGacLocaltion_failed));
3369 * Remove from metabase all read/write/browse permission from certain subdirs
3372 internal static void RestrictIISFolders(HttpContext context) {
3375 HttpWorkerRequest wr = context.WorkerRequest;
3377 Debug.Assert(AppDomainAppId != null);
3379 // Don't do it if we are not running on IIS
3380 if (wr == null || !(wr is System.Web.Hosting.ISAPIWorkerRequest)) {
3384 // Do it only for IIS 5
3385 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
3386 if (!(wr is System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6))
3387 #endif // !FEATURE_PAL
3390 byte[] bufout = new byte[1]; // Just to keep EcbCallISAPI happy
3392 bufin = BitConverter.GetBytes(UnsafeNativeMethods.RESTRICT_BIN);
3393 ret = context.CallISAPI(UnsafeNativeMethods.CallISAPIFunc.RestrictIISFolders, bufin, bufout);
3395 // Cannot pass back any HR from inetinfo.exe because CSyncPipeManager::GetDataFromIIS
3396 // does not support passing back any value when there is an error.
3397 Debug.Trace("RestrictIISFolders", "Cannot restrict folder access for '" + AppDomainAppId + "'.");
3403 // Helper to create instances (public vs. internal/private ctors, see 89781)
3406 internal static Object CreateNonPublicInstance(Type type) {
3407 return CreateNonPublicInstance(type, null);
3410 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3411 internal static Object CreateNonPublicInstance(Type type, Object[] args) {
3412 return Activator.CreateInstance(
3414 BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
3420 internal static Object CreatePublicInstance(Type type) {
3421 return Activator.CreateInstance(type);
3424 #if !DONTUSEFACTORYGENERATOR
3425 // Cache instances of IWebObjectFactory for each Type, which allow us
3426 // to instantiate the objects very efficiently, compared to calling
3427 // Activator.CreateInstance on every call.
3428 private static FactoryGenerator s_factoryGenerator;
3429 private static Hashtable s_factoryCache;
3430 private static bool s_initializedFactory;
3431 private static object s_factoryLock = new Object();
3433 #endif // DONTUSEFACTORYGENERATOR
3436 * Faster implementation of CreatePublicInstance. It generates bits of IL
3437 * on the fly to achieve the improve performance. this should only be used
3438 * in cases where the number of different types to be created is well bounded.
3439 * Otherwise, we would create too much IL, which can bloat the process.
3441 internal static Object FastCreatePublicInstance(Type type) {
3443 #if DONTUSEFACTORYGENERATOR
3444 return CreatePublicInstance(type);
3447 // Only use the factory logic if the assembly is in the GAC, to avoid getting
3448 // assembly conflicts (VSWhidbey 405086)
3449 if (!type.Assembly.GlobalAssemblyCache) {
3450 return CreatePublicInstance(type);
3453 // Create the factory generator on demand
3454 if (!s_initializedFactory) {
3456 // Devdiv 90810 - Synchronize to avoid race condition
3457 lock (s_factoryLock) {
3458 if (!s_initializedFactory) {
3459 s_factoryGenerator = new FactoryGenerator();
3461 // Create the factory cache
3462 s_factoryCache = Hashtable.Synchronized(new Hashtable());
3464 s_initializedFactory = true;
3469 // First, check if it's cached
3470 IWebObjectFactory factory = (IWebObjectFactory)s_factoryCache[type];
3472 if (factory == null) {
3474 Debug.Trace("FastCreatePublicInstance", "Creating generator for type " + type.FullName);
3476 // Create the object factory
3477 factory = s_factoryGenerator.CreateFactory(type);
3479 // Cache the factory
3480 s_factoryCache[type] = factory;
3483 return factory.CreateInstance();
3484 #endif // DONTUSEFACTORYGENERATOR
3487 internal static Object CreatePublicInstance(Type type, Object[] args) {
3489 return Activator.CreateInstance(type);
3491 return Activator.CreateInstance(type, args);
3494 static string GetCurrentUserName() {
3496 return WindowsIdentity.GetCurrent().Name;
3503 void RaiseShutdownWebEventOnce() {
3504 if (!_shutdownWebEventRaised) {
3506 if (!_shutdownWebEventRaised) {
3508 WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationShutdown,
3509 WebApplicationLifetimeEvent.DetailCodeFromShutdownReason(ShutdownReason));
3511 _shutdownWebEventRaised = true;
3517 private static string _DefaultPhysicalPathOnMapPathFailure;
3518 private void RelaxMapPathIfRequired() {
3520 RuntimeConfig config = RuntimeConfig.GetAppConfig();
3521 if (config != null && config.HttpRuntime != null && config.HttpRuntime.RelaxedUrlToFileSystemMapping) {
3522 _DefaultPhysicalPathOnMapPathFailure = Path.Combine(_appDomainAppPath, "NOT_A_VALID_FILESYSTEM_PATH");
3526 internal static bool IsMapPathRelaxed {
3528 return _DefaultPhysicalPathOnMapPathFailure != null;
3531 internal static string GetRelaxedMapPathResult(string originalResult) {
3532 if (!IsMapPathRelaxed) // Feature not enabled?
3533 return originalResult;
3535 if (originalResult == null) // null is never valid: Return the hard coded default physical path
3536 return _DefaultPhysicalPathOnMapPathFailure;
3538 // Does it contain an invalid file-path char?
3539 if (originalResult.IndexOfAny(s_InvalidPhysicalPathChars) >= 0)
3540 return _DefaultPhysicalPathOnMapPathFailure;
3542 // Final check: do the full check to ensure it is valid
3545 if (FileUtil.IsSuspiciousPhysicalPath(originalResult, out pathTooLong) || pathTooLong)
3546 return _DefaultPhysicalPathOnMapPathFailure;
3548 return _DefaultPhysicalPathOnMapPathFailure;
3552 return originalResult;
3557 public enum ApplicationShutdownReason {
3561 HostingEnvironment = 1,
3563 ChangeInGlobalAsax = 2,
3565 ConfigurationChange = 3,
3567 UnloadAppDomainCalled = 4,
3569 ChangeInSecurityPolicyFile = 5,
3571 BinDirChangeOrDirectoryRename = 6,
3573 BrowsersDirChangeOrDirectoryRename = 7,
3575 CodeDirChangeOrDirectoryRename = 8,
3577 ResourcesDirChangeOrDirectoryRename = 9,
3581 PhysicalApplicationPathChanged = 11,
3583 HttpRuntimeClose = 12,
3585 InitializationError = 13,
3587 MaxRecompilationsReached = 14,
3589 BuildManagerChange = 15,