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 Cache _cachePublic;
189 private bool _isOnUNCShare;
190 private Profiler _profiler;
191 private RequestTimeoutManager _timeoutManager;
192 private RequestQueue _requestQueue;
193 private bool _apartmentThreading;
195 private bool _processRequestInApplicationTrust;
196 private bool _disableProcessRequestInApplicationTrust;
197 private bool _isLegacyCas;
202 private bool _beforeFirstRequest = true;
203 private DateTime _firstRequestStartTime;
204 private bool _firstRequestCompleted;
205 private bool _userForcedShutdown;
206 private bool _configInited;
207 private bool _fusionInited;
208 private int _activeRequestCount;
209 private volatile bool _disposingHttpRuntime;
210 private DateTime _lastShutdownAttemptTime;
211 private bool _shutdownInProgress;
212 private String _shutDownStack;
213 private String _shutDownMessage;
214 private ApplicationShutdownReason _shutdownReason = ApplicationShutdownReason.None;
215 private string _trustLevel;
216 private string _wpUserId;
217 private bool _shutdownWebEventRaised;
222 private bool _enableHeaderChecking;
228 private AsyncCallback _requestNotificationCompletionCallback;
229 private AsyncCallback _handlerCompletionCallback;
230 private HttpWorkerRequest.EndOfSendNotification _asyncEndOfSendCallback;
231 private WaitCallback _appDomainUnloadallback;
234 // Initialization error (to be reported on subsequent requests)
237 private Exception _initializationError;
238 private bool _hostingInitFailed; // make such errors non-sticky
239 private Timer _appDomainShutdownTimer = null;
243 // App domain related
246 private String _tempDir;
247 private String _codegenDir;
248 private String _appDomainAppId;
249 private String _appDomainAppPath;
250 private VirtualPath _appDomainAppVPath;
251 private String _appDomainId;
257 private bool _debuggingEnabled = false;
260 // App_Offline.htm support
263 private const string AppOfflineFileName = "App_Offline.htm";
264 private const long MaxAppOfflineFileLength = 1024 * 1024;
265 private byte[] _appOfflineMessage;
268 // Client script support
271 private const string AspNetClientFilesSubDirectory = "asp.netclientfiles";
272 private const string AspNetClientFilesParentVirtualPath = "/aspnet_client/system_web/";
273 private string _clientScriptVirtualPath;
274 private string _clientScriptPhysicalPath;
277 // IIS version and whether we're using the integrated pipeline
279 private static Version _iisVersion;
280 private static bool _useIntegratedPipeline;
285 private static bool _enablePrefetchOptimization;
287 /////////////////////////////////////////////////////////////////////////
288 // 3 steps of initialization:
289 // Init() is called from HttpRuntime cctor
290 // HostingInit() is called by the Hosting Environment
291 // FirstRequestInit() is called on first HTTP request
295 * Context-less initialization (on app domain creation)
297 private void Init() {
300 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
301 throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT));
302 #else // !FEATURE_PAL
304 // Do nothing: FEATURE_PAL environment will always support ASP.NET hosting
305 #endif // !FEATURE_PAL
307 _profiler = new Profiler();
308 _timeoutManager = new RequestTimeoutManager();
309 _wpUserId = GetCurrentUserName();
311 _requestNotificationCompletionCallback = new AsyncCallback(this.OnRequestNotificationCompletion);
312 _handlerCompletionCallback = new AsyncCallback(this.OnHandlerCompletion);
313 _asyncEndOfSendCallback = new HttpWorkerRequest.EndOfSendNotification(this.EndOfSendCallback);
314 _appDomainUnloadallback = new WaitCallback(this.ReleaseResourcesAndUnloadAppDomain);
318 if (GetAppDomainString(".appDomain") != null) {
320 Debug.Assert(HostingEnvironment.IsHosted);
322 _appDomainAppId = GetAppDomainString(".appId");
323 _appDomainAppPath = GetAppDomainString(".appPath");
324 _appDomainAppVPath = VirtualPath.CreateNonRelativeTrailingSlash(GetAppDomainString(".appVPath"));
325 _appDomainId = GetAppDomainString(".domainId");
327 _isOnUNCShare = StringUtil.StringStartsWith(_appDomainAppPath, "\\\\");
329 // init perf counters for this appdomain
330 PerfCounters.Open(_appDomainAppId);
333 Debug.Assert(!HostingEnvironment.IsHosted);
336 // _appDomainAppPath should be set before file change notifications are initialized
337 // DevDiv 248126: Check httpRuntime fcnMode first before we use the registry key
338 _fcm = new FileChangesMonitor(HostingEnvironment.FcnMode);
340 catch (Exception e) {
341 // remember static initalization error
342 InitializationException = e;
346 private void SetUpDataDirectory() {
348 // Set the DataDirectory (see VSWhidbey 226834) with permission (DevDiv 29614)
349 string dataDirectory = Path.Combine(_appDomainAppPath, DataDirectoryName);
350 AppDomain.CurrentDomain.SetData("DataDirectory", dataDirectory,
351 new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dataDirectory));
354 private void DisposeAppDomainShutdownTimer() {
355 Timer timer = _appDomainShutdownTimer;
356 if (timer != null && Interlocked.CompareExchange(ref _appDomainShutdownTimer, null, timer) == timer) {
361 private void AppDomainShutdownTimerCallback(Object state) {
363 DisposeAppDomainShutdownTimer();
364 ShutdownAppDomain(ApplicationShutdownReason.InitializationError, "Initialization Error");
366 catch { } // ignore exceptions
370 * Restart the AppDomain in 10 seconds
372 private void StartAppDomainShutdownTimer() {
373 if (_appDomainShutdownTimer == null && !_shutdownInProgress) {
375 if (_appDomainShutdownTimer == null && !_shutdownInProgress) {
376 _appDomainShutdownTimer = new Timer(
377 new TimerCallback(this.AppDomainShutdownTimerCallback),
388 * Initialization from HostingEnvironment of HTTP independent features
390 private void HostingInit(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) {
391 using (new ApplicationImpersonationContext()) {
393 // To ignore FCN during initialization
394 _firstRequestStartTime = DateTime.UtcNow;
396 SetUpDataDirectory();
398 // Throw an exception about lack of access to app directory early on
399 EnsureAccessToApplicationDirectory();
401 // Monitor renames to directories we are watching, and notifications on the bin directory
403 // Note that this must be the first monitoring that we do of the application directory.
404 // There is a bug in Windows 2000 Server where notifications on UNC shares do not
405 // happen correctly if:
406 // 1. the directory is monitored for regular notifications
407 // 2. the directory is then monitored for directory renames
408 // 3. the directory is monitored again for regular notifications
409 StartMonitoringDirectoryRenamesAndBinDirectory();
411 // Initialize ObjectCacheHost before config is read, since config relies on the cache
412 if (InitializationException == null) {
413 HostingEnvironment.InitializeObjectCacheHost();
417 // Get the configuration needed to minimally initialize
418 // the components required for a complete configuration system,
419 // especially SetTrustLevel.
421 // We want to do this before calling SetUpCodegenDirectory(),
422 // to remove the risk of the config system loading
423 // codegen assemblies in full trust (VSWhidbey 460506)
425 CacheSection cacheSection;
426 TrustSection trustSection;
427 SecurityPolicySection securityPolicySection;
428 CompilationSection compilationSection;
429 HostingEnvironmentSection hostingEnvironmentSection;
430 Exception configInitException;
432 GetInitConfigSections(
435 out securityPolicySection,
436 out compilationSection,
437 out hostingEnvironmentSection,
438 out configInitException);
440 // Once the configuration system is initialized, we can read
441 // the cache configuration settings.
443 // Note that we must do this after we start monitoring directory renames,
444 // as reading config will cause file monitoring on the application directory
447 // Set up the codegen directory for the app. This needs to be done before we process
448 // the policy file, because it needs to replace the $CodeGen$ token.
449 SetUpCodegenDirectory(compilationSection);
451 if(compilationSection != null) {
452 _enablePrefetchOptimization = compilationSection.EnablePrefetchOptimization;
453 if(_enablePrefetchOptimization) {
454 UnsafeNativeMethods.StartPrefetchActivity((uint)StringUtil.GetStringHashCode(_appDomainAppId));
458 // NOTE: after calling SetUpCodegenDirectory(), and until we call SetTrustLevel(), we are at
459 // risk of codegen assemblies being loaded in full trust. No code that might cause
460 // assembly loading should be added here! This is only valid if the legacyCasModel is set
461 // to true in <trust> section.
463 // Throw the original configuration exception from ApplicationManager if configuration is broken.
464 if (appDomainCreationException != null) {
465 throw appDomainCreationException;
468 if (trustSection == null || String.IsNullOrEmpty(trustSection.Level)) {
469 throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "trust"));
472 if (trustSection.LegacyCasModel) {
474 _disableProcessRequestInApplicationTrust = false;
476 // Set code access policy on the app domain
477 SetTrustLevel(trustSection, securityPolicySection);
480 // throw the original config exception if it exists
481 if (configInitException != null)
482 throw configInitException;
486 else if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
487 _trustLevel = "Full";
490 _disableProcessRequestInApplicationTrust = true;
491 // Set code access policy properties of the runtime object
492 SetTrustParameters(trustSection, securityPolicySection, policyLevel);
495 // Configure fusion to use directories set in the app config
496 InitFusion(hostingEnvironmentSection);
498 // set the sliding expiration for URL metadata
499 CachedPathData.InitializeUrlMetadataSlidingExpiration(hostingEnvironmentSection);
501 // Complete initialization of configuration.
502 // Note that this needs to be called after SetTrustLevel,
503 // as it indicates that we have the permission set needed
504 // to correctly run configuration section handlers.
505 // As little config should be read before CompleteInit() as possible.
506 // No section that runs before CompleteInit() should demand permissions,
507 // as the permissions set has not yet determined until SetTrustLevel()
509 HttpConfigurationSystem.CompleteInit();
512 // If an exception occurred loading configuration,
513 // we are now ready to handle exception processing
514 // with the correct trust level set.
516 if (configInitException != null) {
517 throw configInitException;
520 SetThreadPoolLimits();
524 // Initialize the build manager
525 BuildManager.InitializeBuildManager();
527 if(compilationSection != null && compilationSection.ProfileGuidedOptimizations == ProfileGuidedOptimizationsFlags.All) {
528 ProfileOptimization.SetProfileRoot(_codegenDir);
529 ProfileOptimization.StartProfile(profileFileName);
532 // Determine apartment threading setting
533 InitApartmentThreading();
536 InitDebuggingSupport();
538 _processRequestInApplicationTrust = trustSection.ProcessRequestInApplicationTrust;
540 // Init AppDomain Resource Perf Counters
541 AppDomainResourcePerfCounters.Init();
544 RelaxMapPathIfRequired();
546 catch (Exception e) {
547 _hostingInitFailed = true;
548 InitializationException = e;
550 Debug.Trace("AppDomainFactory", "HostingInit failed. " + e.ToString());
552 if ((hostingFlags & HostingEnvironmentFlags.ThrowHostingInitErrors) != 0)
558 internal static Exception InitializationException {
560 return _theRuntime._initializationError;
563 // The exception is "cached" for 10 seconds, then the AppDomain is restarted.
565 _theRuntime._initializationError = value;
566 // In v2.0, we shutdown immediately if hostingInitFailed...so we don't need the timer
567 if (!HostingInitFailed) {
568 _theRuntime.StartAppDomainShutdownTimer();
573 internal static bool HostingInitFailed {
575 return _theRuntime._hostingInitFailed;
579 internal static void InitializeHostingFeatures(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) {
580 _theRuntime.HostingInit(hostingFlags, policyLevel, appDomainCreationException);
583 internal static bool EnableHeaderChecking {
585 return _theRuntime._enableHeaderChecking;
589 internal static bool ProcessRequestInApplicationTrust {
591 return _theRuntime._processRequestInApplicationTrust;
595 internal static bool DisableProcessRequestInApplicationTrust {
597 return _theRuntime._disableProcessRequestInApplicationTrust;
601 internal static bool IsLegacyCas {
603 return _theRuntime._isLegacyCas;
607 internal static byte[] AppOfflineMessage {
609 return _theRuntime._appOfflineMessage;
614 * Initialization on first request (context available)
616 private void FirstRequestInit(HttpContext context) {
617 Exception error = null;
619 if (InitializationException == null && _appDomainId != null) {
621 HttpContext.SetDebugAssertOnAccessToCurrent(true);
624 using (new ApplicationImpersonationContext()) {
625 // Is this necessary? See InitHttpConfiguration
626 CultureInfo savedCulture = Thread.CurrentThread.CurrentCulture;
627 CultureInfo savedUICulture = Thread.CurrentThread.CurrentUICulture;
630 // Ensure config system is initialized
631 InitHttpConfiguration(); // be sure config system is set
633 // Check if applicaton is enabled
634 CheckApplicationEnabled();
636 // Check access to temp compilation directory (under hosting identity)
637 CheckAccessToTempDirectory();
639 // Initialize health monitoring
640 InitializeHealthMonitoring();
642 // Init request queue (after reading config)
645 // configure the profiler according to config
648 // Start heatbeat for Web Event Health Monitoring
649 HealthMonitoringManager.StartHealthMonitoringHeartbeat();
651 // Remove read and browse access of the bin directory
652 RestrictIISFolders(context);
654 // Preload all assemblies from bin (only if required). ASURT 114486
655 PreloadAssembliesFromBin();
657 // Decide whether or not to encode headers. VsWhidbey 257154
658 InitHeaderEncoding();
660 // Force the current encoder + validator to load so that there's a deterministic
661 // place (here) for an exception to occur if there's a load error
662 HttpEncoder.InitializeOnFirstRequest();
663 RequestValidator.InitializeOnFirstRequest();
665 if (context.WorkerRequest is ISAPIWorkerRequestOutOfProc) {
666 // Make sure that the <processModel> section has no errors
667 ProcessModelSection processModel = RuntimeConfig.GetMachineConfig().ProcessModel;
671 Thread.CurrentThread.CurrentUICulture = savedUICulture;
672 SetCurrentThreadCultureWithAssert(savedCulture);
676 catch (ConfigurationException e) {
679 catch (Exception e) {
680 // remember second-phase initialization error
681 error = new HttpException(SR.GetString(SR.XSP_init_error, e.Message), e);
685 HttpContext.SetDebugAssertOnAccessToCurrent(false);
690 if (InitializationException != null) {
691 // throw cached exception. We need to wrap it in a new exception, otherwise
692 // we lose the original stack.
693 throw new HttpException(InitializationException.Message, InitializationException);
695 else if (error != null) {
696 InitializationException = error;
697 // throw new exception
701 AddAppDomainTraceMessage("FirstRequestInit");
704 [SecurityPermission(SecurityAction.Assert, ControlThread = true)]
705 internal static void SetCurrentThreadCultureWithAssert(CultureInfo cultureInfo) {
706 Thread.CurrentThread.CurrentCulture = cultureInfo;
709 private void EnsureFirstRequestInit(HttpContext context) {
710 if (_beforeFirstRequest) {
712 if (_beforeFirstRequest) {
713 _firstRequestStartTime = DateTime.UtcNow;
714 FirstRequestInit(context);
715 _beforeFirstRequest = false;
716 context.FirstRequest = true;
722 private void EnsureAccessToApplicationDirectory() {
723 if (!FileUtil.DirectoryAccessible(_appDomainAppPath)) {
725 if (_appDomainAppPath.IndexOf('?') >= 0) {
726 // Possible Unicode when not supported
727 throw new HttpException(SR.GetString(SR.Access_denied_to_unicode_app_dir, _appDomainAppPath));
730 throw new HttpException(SR.GetString(SR.Access_denied_to_app_dir, _appDomainAppPath));
735 private void StartMonitoringDirectoryRenamesAndBinDirectory() {
736 _fcm.StartMonitoringDirectoryRenamesAndBinDirectory(AppDomainAppPathInternal, new FileChangeEventHandler(this.OnCriticalDirectoryChange));
740 // Monitor a local resources subdirectory and unload appdomain when it changes
742 internal static void StartListeningToLocalResourcesDirectory(VirtualPath virtualDir) {
743 #if !FEATURE_PAL // FEATURE_PAL does not enable file change notification
744 _theRuntime._fcm.StartListeningToLocalResourcesDirectory(virtualDir);
745 #endif // !FEATURE_PAL
749 // Get the configuration needed to minimally initialize
750 // the components required for a complete configuration system,
752 // Note that if the application configuration file has an error,
753 // AppLKGConfig will still retreive any valid configuration from
754 // that file, or from location directives that apply to the
755 // application path. This implies that an administrator can
756 // lock down an application's trust level in root web.config,
757 // and it will still take effect if the application's web.config
760 private void GetInitConfigSections(
761 out CacheSection cacheSection,
762 out TrustSection trustSection,
763 out SecurityPolicySection securityPolicySection,
764 out CompilationSection compilationSection,
765 out HostingEnvironmentSection hostingEnvironmentSection,
766 out Exception initException) {
770 securityPolicySection = null;
771 compilationSection = null;
772 hostingEnvironmentSection = null;
773 initException = null;
775 // AppLKGConfig is guaranteed to not throw an exception.
776 RuntimeConfig appLKGConfig = RuntimeConfig.GetAppLKGConfig();
778 // AppConfig may throw an exception.
779 RuntimeConfig appConfig = null;
781 appConfig = RuntimeConfig.GetAppConfig();
783 catch (Exception e) {
788 if (appConfig != null) {
790 cacheSection = appConfig.Cache;
792 catch (Exception e) {
793 if (initException == null) {
799 if (cacheSection == null) {
800 cacheSection = appLKGConfig.Cache;
804 if (appConfig != null) {
806 trustSection = appConfig.Trust;
808 catch (Exception e) {
809 if (initException == null) {
815 if (trustSection == null) {
816 trustSection = appLKGConfig.Trust;
819 // SecurityPolicy section
820 if (appConfig != null) {
822 securityPolicySection = appConfig.SecurityPolicy;
824 catch (Exception e) {
825 if (initException == null) {
831 if (securityPolicySection == null) {
832 securityPolicySection = appLKGConfig.SecurityPolicy;
835 // Compilation section
836 if (appConfig != null) {
838 compilationSection = appConfig.Compilation;
840 catch (Exception e) {
841 if (initException == null) {
847 if (compilationSection == null) {
848 compilationSection = appLKGConfig.Compilation;
851 // HostingEnvironment section
852 if (appConfig != null) {
854 hostingEnvironmentSection = appConfig.HostingEnvironment;
856 catch (Exception e) {
857 if (initException == null) {
863 if (hostingEnvironmentSection == null) {
864 hostingEnvironmentSection = appLKGConfig.HostingEnvironment;
868 // Set up the codegen directory for the app
869 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This call site is trusted.")]
870 private void SetUpCodegenDirectory(CompilationSection compilationSection) {
871 AppDomain appDomain = Thread.GetDomain();
875 // devdiv 1038337. Passing the corresponding IsDevelopmentEnvironment flag to ConstructSimpleAppName
876 string simpleAppName = System.Web.Hosting.AppManagerAppDomainFactory.ConstructSimpleAppName(
877 AppDomainAppVirtualPath, HostingEnvironment.IsDevelopmentEnvironment);
879 string tempDirectory = null;
881 // These variables are used for error handling
882 string tempDirAttribName = null;
883 string configFileName = null;
884 int configLineNumber = 0;
886 if (compilationSection != null && !String.IsNullOrEmpty(compilationSection.TempDirectory)) {
887 tempDirectory = compilationSection.TempDirectory;
889 compilationSection.GetTempDirectoryErrorInfo(out tempDirAttribName,
890 out configFileName, out configLineNumber);
893 if (tempDirectory != null) {
894 tempDirectory = tempDirectory.Trim();
896 if (!Path.IsPathRooted(tempDirectory)) {
897 // Make sure the path is not relative (VSWhidbey 260075)
898 tempDirectory = null;
902 // Canonicalize it to avoid problems with spaces (VSWhidbey 229873)
903 tempDirectory = new DirectoryInfo(tempDirectory).FullName;
906 tempDirectory = null;
910 if (tempDirectory == null) {
911 throw new ConfigurationErrorsException(
912 SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
913 configFileName, configLineNumber);
917 System.UInt32 length = 0;
918 StringBuilder sb = null;
921 // Get the required length
922 bRet = UnsafeNativeMethods.GetUserTempDirectory(
923 UnsafeNativeMethods.DeploymentDirectoryType.ddtInstallationDependentDirectory,
927 // now, allocate the string
928 sb = new StringBuilder ((int)length);
930 // call again to get the value
931 bRet = UnsafeNativeMethods.GetUserTempDirectory(
932 UnsafeNativeMethods.DeploymentDirectoryType.ddtInstallationDependentDirectory,
937 throw new ConfigurationException(
938 HttpRuntime.FormatResourceString(SR.Invalid_temp_directory, tempDirAttribName));
941 tempDirectory = Path.Combine(sb.ToString(), codegenDirName);
944 // Always try to create the ASP.Net temp directory for FEATURE_PAL
945 #endif // FEATURE_PAL
947 // Create the config-specified directory if needed
949 Directory.CreateDirectory(tempDirectory);
951 catch (Exception e) {
952 throw new ConfigurationErrorsException(
953 SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
955 configFileName, configLineNumber);
960 tempDirectory = Path.Combine(s_installDirectory, codegenDirName);
962 #endif // !FEATURE_PAL
964 // If we don't have write access to the codegen dir, use the TEMP dir instead.
965 // This will allow non-admin users to work in hosting scenarios (e.g. Venus, aspnet_compiler)
966 if (!System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory)) {
968 // Don't do this if we are not in a CBM scenario and we're in a service (!UserInteractive),
969 // as TEMP could point to unwanted places.
971 #if !FEATURE_PAL // always fail here
972 if ((!BuildManagerHost.InClientBuildManager) && (!Environment.UserInteractive))
973 #endif // !FEATURE_PAL
975 throw new HttpException(SR.GetString(SR.No_codegen_access,
976 System.Web.UI.Util.GetCurrentAccountName(), tempDirectory));
979 tempDirectory = Path.GetTempPath();
980 Debug.Assert(System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory));
981 tempDirectory = Path.Combine(tempDirectory, codegenDirName);
984 _tempDir = tempDirectory;
986 codegenBase = Path.Combine(tempDirectory, simpleAppName);
988 #pragma warning disable 0618 // To avoid deprecation warning
989 appDomain.SetDynamicBase(codegenBase);
990 #pragma warning restore 0618
992 _codegenDir = Thread.GetDomain().DynamicDirectory;
994 // Create the codegen directory if needed
995 Directory.CreateDirectory(_codegenDir);
998 private void InitFusion(HostingEnvironmentSection hostingEnvironmentSection) {
1000 AppDomain appDomain = Thread.GetDomain();
1002 // If there is a double backslash in the string, get rid of it (ASURT 122191)
1003 // Make sure to skip the first char, to avoid breaking the UNC case
1004 string appDomainAppPath = _appDomainAppPath;
1005 if (appDomainAppPath.IndexOf(DoubleDirectorySeparatorString, 1, StringComparison.Ordinal) >= 1) {
1006 appDomainAppPath = appDomainAppPath[0] + appDomainAppPath.Substring(1).Replace(DoubleDirectorySeparatorString,
1007 DirectorySeparatorString);
1010 #pragma warning disable 0618 // To avoid deprecation warning
1011 // Allow assemblies from 'bin' to be loaded
1012 appDomain.AppendPrivatePath(appDomainAppPath + BinDirectoryName);
1013 #pragma warning restore 0618
1015 // If shadow copying was disabled via config, turn it off (DevDiv 30864)
1016 if (hostingEnvironmentSection != null && !hostingEnvironmentSection.ShadowCopyBinAssemblies) {
1017 #pragma warning disable 0618 // To avoid deprecation warning
1018 appDomain.ClearShadowCopyPath();
1019 #pragma warning restore 0618
1022 // enable shadow-copying from bin
1023 #pragma warning disable 0618 // To avoid deprecation warning
1024 appDomain.SetShadowCopyPath(appDomainAppPath + BinDirectoryName);
1025 #pragma warning restore 0618
1028 // Get rid of the last part of the directory (the app name), since it will
1030 string parentDir = Directory.GetParent(_codegenDir).FullName;
1031 #pragma warning disable 0618 // To avoid deprecation warning
1032 appDomain.SetCachePath(parentDir);
1033 #pragma warning restore 0618
1035 _fusionInited = true;
1038 private void InitRequestQueue() {
1039 RuntimeConfig config = RuntimeConfig.GetAppConfig();
1040 HttpRuntimeSection runtimeConfig = config.HttpRuntime;
1041 ProcessModelSection processConfig = config.ProcessModel;
1043 if (processConfig.AutoConfig) {
1044 _requestQueue = new RequestQueue(
1045 88 * processConfig.CpuCount,
1046 76 * processConfig.CpuCount,
1047 runtimeConfig.AppRequestQueueLimit,
1048 processConfig.ClientConnectedCheck);
1052 // Configuration section handlers cannot validate values based on values
1053 // in other configuration sections, so we validate minFreeThreads and
1054 // minLocalRequestFreeThreads here.
1055 int maxThreads = (processConfig.MaxWorkerThreadsTimesCpuCount < processConfig.MaxIoThreadsTimesCpuCount) ? processConfig.MaxWorkerThreadsTimesCpuCount : processConfig.MaxIoThreadsTimesCpuCount;
1056 // validate minFreeThreads
1057 if (runtimeConfig.MinFreeThreads >= maxThreads) {
1058 if (runtimeConfig.ElementInformation.Properties["minFreeThreads"].LineNumber == 0) {
1059 if (processConfig.ElementInformation.Properties["maxWorkerThreads"].LineNumber != 0) {
1060 throw new ConfigurationErrorsException(SR.GetString(SR.Thread_pool_limit_must_be_greater_than_minFreeThreads, runtimeConfig.MinFreeThreads.ToString(CultureInfo.InvariantCulture)),
1061 processConfig.ElementInformation.Properties["maxWorkerThreads"].Source,
1062 processConfig.ElementInformation.Properties["maxWorkerThreads"].LineNumber);
1065 throw new ConfigurationErrorsException(SR.GetString(SR.Thread_pool_limit_must_be_greater_than_minFreeThreads, runtimeConfig.MinFreeThreads.ToString(CultureInfo.InvariantCulture)),
1066 processConfig.ElementInformation.Properties["maxIoThreads"].Source,
1067 processConfig.ElementInformation.Properties["maxIoThreads"].LineNumber);
1071 throw new ConfigurationErrorsException(SR.GetString(SR.Min_free_threads_must_be_under_thread_pool_limits, maxThreads.ToString(CultureInfo.InvariantCulture)),
1072 runtimeConfig.ElementInformation.Properties["minFreeThreads"].Source,
1073 runtimeConfig.ElementInformation.Properties["minFreeThreads"].LineNumber);
1076 // validate minLocalRequestFreeThreads
1077 if (runtimeConfig.MinLocalRequestFreeThreads > runtimeConfig.MinFreeThreads) {
1078 if (runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].LineNumber == 0) {
1079 throw new ConfigurationErrorsException(SR.GetString(SR.Local_free_threads_cannot_exceed_free_threads),
1080 processConfig.ElementInformation.Properties["minFreeThreads"].Source,
1081 processConfig.ElementInformation.Properties["minFreeThreads"].LineNumber);
1084 throw new ConfigurationErrorsException(SR.GetString(SR.Local_free_threads_cannot_exceed_free_threads),
1085 runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].Source,
1086 runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].LineNumber);
1090 _requestQueue = new RequestQueue(
1091 runtimeConfig.MinFreeThreads,
1092 runtimeConfig.MinLocalRequestFreeThreads,
1093 runtimeConfig.AppRequestQueueLimit,
1094 processConfig.ClientConnectedCheck);
1098 private void InitApartmentThreading() {
1099 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1101 if (runtimeConfig != null) {
1102 _apartmentThreading = runtimeConfig.ApartmentThreading;
1105 _apartmentThreading = false;
1109 private void InitTrace(HttpContext context) {
1110 TraceSection traceConfig = RuntimeConfig.GetAppConfig().Trace;
1112 Profile.RequestsToProfile = traceConfig.RequestLimit;
1113 Profile.PageOutput = traceConfig.PageOutput;
1114 Profile.OutputMode = TraceMode.SortByTime;
1115 if (traceConfig.TraceMode == TraceDisplayMode.SortByCategory)
1116 Profile.OutputMode = TraceMode.SortByCategory;
1118 Profile.LocalOnly = traceConfig.LocalOnly;
1119 Profile.IsEnabled = traceConfig.Enabled;
1120 Profile.MostRecent = traceConfig.MostRecent;
1123 // the first request's context is created before InitTrace, so
1124 // we need to set this manually. (ASURT 93730)
1125 context.TraceIsEnabled = traceConfig.Enabled;
1126 TraceContext.SetWriteToDiagnosticsTrace(traceConfig.WriteToDiagnosticsTrace);
1129 private void InitDebuggingSupport() {
1130 CompilationSection compConfig = RuntimeConfig.GetAppConfig().Compilation;
1131 _debuggingEnabled = compConfig.Debug;
1135 * Pre-load all the bin assemblies if we're impersonated. This way, if user code
1136 * calls Assembly.Load while impersonated, the assembly will already be loaded, and
1137 * we won't fail due to lack of permissions on the codegen dir (see ASURT 114486)
1139 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1140 private void PreloadAssembliesFromBin() {
1141 bool appClientImpersonationEnabled = false;
1143 if (!_isOnUNCShare) {
1144 // if not on UNC share check if config has impersonation enabled (without userName)
1145 IdentitySection c = RuntimeConfig.GetAppConfig().Identity;
1146 if (c.Impersonate && c.ImpersonateToken == IntPtr.Zero)
1147 appClientImpersonationEnabled = true;
1150 if (!appClientImpersonationEnabled)
1153 // Get the path to the bin directory
1154 string binPath = HttpRuntime.BinDirectoryInternal;
1156 DirectoryInfo binPathDirectory = new DirectoryInfo(binPath);
1158 if (!binPathDirectory.Exists)
1161 PreloadAssembliesFromBinRecursive(binPathDirectory);
1164 private void PreloadAssembliesFromBinRecursive(DirectoryInfo dirInfo) {
1166 FileInfo[] binDlls = dirInfo.GetFiles("*.dll");
1168 // Pre-load all the assemblies, ignoring all exceptions
1169 foreach (FileInfo fi in binDlls) {
1170 try { Assembly.Load(System.Web.UI.Util.GetAssemblyNameFromFileName(fi.Name)); }
1171 catch (FileNotFoundException) {
1172 // If Load failed, try LoadFrom (VSWhidbey 493725)
1173 try { Assembly.LoadFrom(fi.FullName); }
1179 // Recurse on the subdirectories
1180 DirectoryInfo[] subDirs = dirInfo.GetDirectories();
1181 foreach (DirectoryInfo di in subDirs) {
1182 PreloadAssembliesFromBinRecursive(di);
1186 private void SetAutoConfigLimits(ProcessModelSection pmConfig) {
1187 // check if the current limits are ok
1188 int workerMax, ioMax;
1189 ThreadPool.GetMaxThreads(out workerMax, out ioMax);
1191 // only set if different
1192 if (pmConfig.DefaultMaxWorkerThreadsForAutoConfig != workerMax || pmConfig.DefaultMaxIoThreadsForAutoConfig != ioMax) {
1193 Debug.Trace("ThreadPool", "SetThreadLimit: from " + workerMax + "," + ioMax + " to " + pmConfig.DefaultMaxWorkerThreadsForAutoConfig + "," + pmConfig.DefaultMaxIoThreadsForAutoConfig);
1194 UnsafeNativeMethods.SetClrThreadPoolLimits(pmConfig.DefaultMaxWorkerThreadsForAutoConfig, pmConfig.DefaultMaxIoThreadsForAutoConfig, true);
1197 // this is the code equivalent of setting maxconnection
1198 // Dev11 141729: Make autoConfig scale by default
1199 // Dev11 144842: PERF: Consider removing Max connection limit or changing the default value
1200 System.Net.ServicePointManager.DefaultConnectionLimit = Int32.MaxValue;
1202 // we call InitRequestQueue later, from FirstRequestInit, and set minFreeThreads and minLocalRequestFreeThreads
1205 private void SetThreadPoolLimits() {
1207 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
1209 if (pmConfig.AutoConfig) {
1210 // use recommendation in http://support.microsoft.com/?id=821268
1211 SetAutoConfigLimits(pmConfig);
1213 else if (pmConfig.MaxWorkerThreadsTimesCpuCount > 0 && pmConfig.MaxIoThreadsTimesCpuCount > 0) {
1214 // check if the current limits are ok
1215 int workerMax, ioMax;
1216 ThreadPool.GetMaxThreads(out workerMax, out ioMax);
1218 // only set if different
1219 if (pmConfig.MaxWorkerThreadsTimesCpuCount != workerMax || pmConfig.MaxIoThreadsTimesCpuCount != ioMax) {
1220 Debug.Trace("ThreadPool", "SetThreadLimit: from " + workerMax + "," + ioMax + " to " + pmConfig.MaxWorkerThreadsTimesCpuCount + "," + pmConfig.MaxIoThreadsTimesCpuCount);
1221 UnsafeNativeMethods.SetClrThreadPoolLimits(pmConfig.MaxWorkerThreadsTimesCpuCount, pmConfig.MaxIoThreadsTimesCpuCount, false);
1225 if (pmConfig.MinWorkerThreadsTimesCpuCount > 0 || pmConfig.MinIoThreadsTimesCpuCount > 0) {
1226 int currentMinWorkerThreads, currentMinIoThreads;
1227 ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIoThreads);
1229 int newMinWorkerThreads = pmConfig.MinWorkerThreadsTimesCpuCount > 0 ? pmConfig.MinWorkerThreadsTimesCpuCount : currentMinWorkerThreads;
1230 int newMinIoThreads = pmConfig.MinIoThreadsTimesCpuCount > 0 ? pmConfig.MinIoThreadsTimesCpuCount : currentMinIoThreads;
1232 if (newMinWorkerThreads > 0 && newMinIoThreads > 0
1233 && (newMinWorkerThreads != currentMinWorkerThreads || newMinIoThreads != currentMinIoThreads))
1234 ThreadPool.SetMinThreads(newMinWorkerThreads, newMinIoThreads);
1241 internal static void CheckApplicationEnabled() {
1242 // process App_Offline.htm file
1243 string appOfflineFile = Path.Combine(_theRuntime._appDomainAppPath, AppOfflineFileName);
1244 bool appOfflineFileFound = false;
1246 // monitor even if doesn't exist
1247 _theRuntime._fcm.StartMonitoringFile(appOfflineFile, new FileChangeEventHandler(_theRuntime.OnAppOfflineFileChange));
1249 // read the file into memory
1251 if (File.Exists(appOfflineFile)) {
1252 Debug.Trace("AppOffline", "File " + appOfflineFile + " exists. Using it.");
1254 using (FileStream fs = new FileStream(appOfflineFile, FileMode.Open, FileAccess.Read, FileShare.Read)) {
1255 if (fs.Length <= MaxAppOfflineFileLength) {
1256 int length = (int)fs.Length;
1259 byte[] message = new byte[length];
1261 if (fs.Read(message, 0, length) == length) {
1262 // remember the message
1263 _theRuntime._appOfflineMessage = message;
1264 appOfflineFileFound = true;
1269 appOfflineFileFound = true;
1270 _theRuntime._appOfflineMessage = new byte[0];
1277 // ignore any IO errors reading the file
1280 // throw if there is a valid App_Offline file
1281 if (appOfflineFileFound) {
1282 throw new HttpException(503, String.Empty);
1285 // process the config setting
1286 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1287 if (!runtimeConfig.Enable) {
1288 // throw 404 on first request init -- this will get cached until config changes
1289 throw new HttpException(404, String.Empty);
1293 [FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
1294 private void CheckAccessToTempDirectory() {
1295 // The original check (in HostingInit) was done under process identity
1296 // this time we do it under hosting identity
1297 if (HostingEnvironment.HasHostingIdentity) {
1298 using (new ApplicationImpersonationContext()) {
1299 if (!System.Web.UI.Util.HasWriteAccessToDirectory(_tempDir)) {
1300 throw new HttpException(SR.GetString(SR.No_codegen_access,
1301 System.Web.UI.Util.GetCurrentAccountName(), _tempDir));
1307 private void InitializeHealthMonitoring() {
1308 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
1309 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
1310 int deadLockInterval = (int)pmConfig.ResponseDeadlockInterval.TotalSeconds;
1311 int requestQueueLimit = pmConfig.RequestQueueLimit;
1312 Debug.Trace("HealthMonitor", "Initalizing: ResponseDeadlockInterval=" + deadLockInterval);
1313 UnsafeNativeMethods.InitializeHealthMonitor(deadLockInterval, requestQueueLimit);
1314 #endif // !FEATURE_PAL
1317 private static void InitHttpConfiguration() {
1318 if (!_theRuntime._configInited) {
1319 _theRuntime._configInited = true;
1321 HttpConfigurationSystem.EnsureInit(null, true, true);
1323 // whenever possible report errors in the user's culture (from machine.config)
1324 // Note: this thread's culture is saved/restored during FirstRequestInit, so this is safe
1327 GlobalizationSection globConfig = RuntimeConfig.GetAppLKGConfig().Globalization;
1328 if (globConfig != null) {
1329 if (!String.IsNullOrEmpty(globConfig.Culture) &&
1330 !StringUtil.StringStartsWithIgnoreCase(globConfig.Culture, "auto"))
1331 SetCurrentThreadCultureWithAssert(HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.Culture));
1333 if (!String.IsNullOrEmpty(globConfig.UICulture) &&
1334 !StringUtil.StringStartsWithIgnoreCase(globConfig.UICulture, "auto"))
1335 Thread.CurrentThread.CurrentUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
1338 // check for errors in <processModel> section
1339 RuntimeConfig appConfig = RuntimeConfig.GetAppConfig();
1340 object section = appConfig.ProcessModel;
1341 // check for errors in <hostingEnvironment> section
1342 section = appConfig.HostingEnvironment;
1346 private void InitHeaderEncoding() {
1347 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1348 _enableHeaderChecking = runtimeConfig.EnableHeaderChecking;
1351 private static void SetAutogenKeys() {
1352 #if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
1353 byte[] bKeysRandom = new byte[s_autogenKeys.Length];
1354 byte[] bKeysStored = new byte[s_autogenKeys.Length];
1355 bool fGetStoredKeys = false;
1356 RNGCryptoServiceProvider randgen = new RNGCryptoServiceProvider();
1358 // Gernerate random keys
1359 randgen.GetBytes(bKeysRandom);
1361 // If getting stored keys via WorkerRequest object failed, get it directly
1362 if (!fGetStoredKeys)
1363 fGetStoredKeys = (UnsafeNativeMethods.EcbCallISAPI(IntPtr.Zero, UnsafeNativeMethods.CallISAPIFunc.GetAutogenKeys,
1364 bKeysRandom, bKeysRandom.Length, bKeysStored, bKeysStored.Length) == 1);
1366 // If we managed to get stored keys, copy them in; else use random keys
1368 Buffer.BlockCopy(bKeysStored, 0, s_autogenKeys, 0, s_autogenKeys.Length);
1370 Buffer.BlockCopy(bKeysRandom, 0, s_autogenKeys, 0, s_autogenKeys.Length);
1371 #endif // !FEATURE_PAL
1374 internal static void IncrementActivePipelineCount() {
1375 Interlocked.Increment(ref _theRuntime._activeRequestCount);
1376 HostingEnvironment.IncrementBusyCount();
1379 internal static void DecrementActivePipelineCount() {
1380 HostingEnvironment.DecrementBusyCount();
1381 Interlocked.Decrement(ref _theRuntime._activeRequestCount);
1384 internal static void PopulateIISVersionInformation() {
1385 if (IsEngineLoaded) {
1387 bool fIsIntegratedMode;
1388 UnsafeIISMethods.MgdGetIISVersionInformation(out dwVersion, out fIsIntegratedMode);
1390 if (dwVersion != 0) {
1391 // High word is the major version; low word is the minor version (this is MAKELONG format)
1392 _iisVersion = new Version((int)(dwVersion >> 16), (int)(dwVersion & 0xffff));
1393 _useIntegratedPipeline = fIsIntegratedMode;
1398 // 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.
1399 // Should also return the correct version for IIS Express.
1400 public static Version IISVersion {
1406 // DevDivBugs 190952: public method for querying runtime pipeline mode
1407 public static bool UsingIntegratedPipeline {
1409 return UseIntegratedPipeline;
1413 internal static bool UseIntegratedPipeline {
1415 return _useIntegratedPipeline;
1419 internal static bool EnablePrefetchOptimization {
1421 return _enablePrefetchOptimization;
1426 * Process one step of the integrated pipeline
1430 internal static RequestNotificationStatus ProcessRequestNotification(IIS7WorkerRequest wr, HttpContext context)
1432 return _theRuntime.ProcessRequestNotificationPrivate(wr, context);
1435 private RequestNotificationStatus ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) {
1436 RequestNotificationStatus status = RequestNotificationStatus.Pending;
1438 int currentModuleIndex;
1439 bool isPostNotification;
1440 int currentNotification;
1442 // setup the HttpContext for this event/module combo
1443 UnsafeIISMethods.MgdGetCurrentNotificationInfo(wr.RequestContext, out currentModuleIndex, out isPostNotification, out currentNotification);
1445 context.CurrentModuleIndex = currentModuleIndex;
1446 context.IsPostNotification = isPostNotification;
1447 context.CurrentNotification = (RequestNotification) currentNotification;
1449 Debug.Trace("PipelineRuntime", "HttpRuntime::ProcessRequestNotificationPrivate: notification=" + context.CurrentNotification.ToString()
1450 + ", isPost=" + context.IsPostNotification
1451 + ", moduleIndex=" + context.CurrentModuleIndex);
1454 IHttpHandler handler = null;
1455 if (context.NeedToInitializeApp()) {
1457 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
1458 "*** FirstNotification " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
1459 + ": _appDomainAppId=" + _appDomainAppId);
1461 // First request initialization
1463 EnsureFirstRequestInit(context);
1466 // If we are handling a DEBUG request, ignore the FirstRequestInit exception.
1467 // This allows the HttpDebugHandler to execute, and lets the debugger attach to
1468 // the process (VSWhidbey 358135)
1469 if (!context.Request.IsDebuggingRequest) {
1474 context.Response.InitResponseWriter();
1475 handler = HttpApplicationFactory.GetApplicationInstance(context);
1476 if (handler == null)
1477 throw new HttpException(SR.GetString(SR.Unable_create_app_object));
1479 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, handler.GetType().FullName, "Start");
1481 HttpApplication app = handler as HttpApplication;
1483 // associate the context with an application instance
1484 app.AssignContext(context);
1488 // this may throw, and should be called after app initialization
1489 wr.SynchronizeVariables(context);
1491 if (context.ApplicationInstance != null) {
1493 IAsyncResult ar = context.ApplicationInstance.BeginProcessRequestNotification(context, _requestNotificationCompletionCallback);
1495 if (ar.CompletedSynchronously) {
1496 status = RequestNotificationStatus.Continue;
1499 else if (handler != null) {
1500 // HttpDebugHandler is processed here
1501 handler.ProcessRequest(context);
1502 status = RequestNotificationStatus.FinishRequest;
1505 status = RequestNotificationStatus.Continue;
1508 catch (Exception e) {
1509 status = RequestNotificationStatus.FinishRequest;
1510 context.Response.InitResponseWriter();
1511 // errors are handled in HttpRuntime::FinishRequestNotification
1512 context.AddError(e);
1515 if (status != RequestNotificationStatus.Pending) {
1516 // we completed synchronously
1517 FinishRequestNotification(wr, context, ref status);
1521 Debug.Trace("PipelineRuntime", "HttpRuntime::ProcessRequestNotificationPrivate: status=" + status.ToString());
1527 private void FinishRequestNotification(IIS7WorkerRequest wr, HttpContext context, ref RequestNotificationStatus status) {
1529 Debug.Assert(status != RequestNotificationStatus.Pending, "status != RequestNotificationStatus.Pending");
1531 HttpApplication app = context.ApplicationInstance;
1533 if (context.NotificationContext.RequestCompleted) {
1534 status = RequestNotificationStatus.FinishRequest;
1537 // check if the app offline or whether an error has occurred, and report the condition
1538 context.ReportRuntimeErrorIfExists(ref status);
1540 // we do not return FinishRequest for LogRequest or EndRequest
1541 if (status == RequestNotificationStatus.FinishRequest
1542 && (context.CurrentNotification == RequestNotification.LogRequest
1543 || context.CurrentNotification == RequestNotification.EndRequest)) {
1544 status = RequestNotificationStatus.Continue;
1547 IntPtr requestContext = wr.RequestContext;
1548 bool sendHeaders = UnsafeIISMethods.MgdIsLastNotification(requestContext, status);
1550 context.Response.UpdateNativeResponse(sendHeaders);
1552 catch(Exception e) {
1553 // if we catch an exception here then
1554 // i) clear cached response body bytes on the worker request
1555 // ii) clear the managed headers, the IIS native headers, the mangaged httpwriter response buffers, and the native IIS response buffers
1556 // iii) attempt to format the exception and write it to the response
1557 wr.UnlockCachedResponseBytes();
1558 context.AddError(e);
1559 context.ReportRuntimeErrorIfExists(ref status);
1561 context.Response.UpdateNativeResponse(sendHeaders);
1568 context.FinishPipelineRequest();
1571 // Perf optimization: dispose managed context if possible (no need to try if status is pending)
1572 if (status != RequestNotificationStatus.Pending) {
1573 PipelineRuntime.DisposeHandler(context, requestContext, status);
1577 internal static void FinishPipelineRequest(HttpContext context) {
1578 // Remember that first request is done
1579 _theRuntime._firstRequestCompleted = true;
1581 // need to raise OnRequestCompleted while within the ThreadContext so that things like User, CurrentCulture, etc. are available
1582 context.RaiseOnRequestCompleted();
1584 context.Request.Dispose();
1585 context.Response.Dispose();
1586 HttpApplication app = context.ApplicationInstance;
1588 ThreadContext threadContext = context.IndicateCompletionContext;
1589 if (threadContext != null) {
1590 if (!threadContext.HasBeenDisassociatedFromThread) {
1591 lock (threadContext) {
1592 if (!threadContext.HasBeenDisassociatedFromThread) {
1593 threadContext.DisassociateFromCurrentThread();
1594 context.IndicateCompletionContext = null;
1595 context.InIndicateCompletion = false;
1600 app.ReleaseAppInstance();
1603 SetExecutionTimePerformanceCounter(context);
1604 UpdatePerfCounters(context.Response.StatusCode);
1605 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
1607 // In case of a HostingInit() error, app domain should not stick around
1608 if (HostingInitFailed) {
1609 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of HostingInit error");
1610 ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, "HostingInit error");
1616 * Process one request
1618 private void ProcessRequestInternal(HttpWorkerRequest wr) {
1619 // Count active requests
1620 Interlocked.Increment(ref _activeRequestCount);
1622 if (_disposingHttpRuntime) {
1623 // Dev11 333176: An appdomain is unloaded before all requests are served, resulting in System.AppDomainUnloadedException during isapi completion callback
1625 // HttpRuntim.Dispose could have already finished on a different thread when we had no active requests
1626 // In this case we are about to start or already started unloading the appdomain so we will reject the request the safest way possible
1628 wr.SendStatus(503, "Server Too Busy");
1629 wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
1630 byte[] body = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>");
1631 wr.SendResponseFromMemory(body, body.Length);
1632 // this will flush synchronously because of HttpRuntime.ShutdownInProgress
1633 wr.FlushResponse(true);
1636 Interlocked.Decrement(ref _activeRequestCount);
1641 // Construct the Context on HttpWorkerRequest, hook everything together
1642 HttpContext context;
1645 context = new HttpContext(wr, false /* initResponseWriter */);
1649 // If we fail to create the context for any reason, send back a 400 to make sure
1650 // the request is correctly closed (relates to VSUQFE3962)
1651 wr.SendStatus(400, "Bad Request");
1652 wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
1653 byte[] body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
1654 wr.SendResponseFromMemory(body, body.Length);
1655 wr.FlushResponse(true);
1659 Interlocked.Decrement(ref _activeRequestCount);
1663 wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
1665 HostingEnvironment.IncrementBusyCount();
1668 // First request initialization
1670 EnsureFirstRequestInit(context);
1673 // If we are handling a DEBUG request, ignore the FirstRequestInit exception.
1674 // This allows the HttpDebugHandler to execute, and lets the debugger attach to
1675 // the process (VSWhidbey 358135)
1676 if (!context.Request.IsDebuggingRequest) {
1681 // Init response writer (after we have config in first request init)
1682 // no need for impersonation as it is handled in config system
1683 context.Response.InitResponseWriter();
1685 // Get application instance
1686 IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
1689 throw new HttpException(SR.GetString(SR.Unable_create_app_object));
1691 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName, "Start");
1693 if (app is IHttpAsyncHandler) {
1694 // asynchronous handler
1695 IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
1696 context.AsyncAppHandler = asyncHandler;
1697 asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
1700 // synchronous handler
1701 app.ProcessRequest(context);
1702 FinishRequest(context.WorkerRequest, context, null);
1705 catch (Exception e) {
1706 context.Response.InitResponseWriter();
1707 FinishRequest(wr, context, e);
1711 private void RejectRequestInternal(HttpWorkerRequest wr, bool silent) {
1712 // Construct the Context on HttpWorkerRequest, hook everything together
1713 HttpContext context = new HttpContext(wr, false /* initResponseWriter */);
1714 wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
1716 // Count active requests
1717 Interlocked.Increment(ref _activeRequestCount);
1718 HostingEnvironment.IncrementBusyCount();
1721 context.Response.InitResponseWriter();
1722 FinishRequest(wr, context, null);
1725 PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.REQUESTS_REJECTED);
1726 PerfCounters.IncrementCounter(AppPerfCounter.APP_REQUESTS_REJECTED);
1728 throw new HttpException(503, SR.GetString(SR.Server_too_busy));
1730 catch (Exception e) {
1731 context.Response.InitResponseWriter();
1732 FinishRequest(wr, context, e);
1737 internal static void ReportAppOfflineErrorMessage(HttpResponse response, byte[] appOfflineMessage) {
1738 response.StatusCode = 503;
1739 response.ContentType = "text/html";
1740 response.AddHeader("Retry-After", "3600");
1741 response.OutputStream.Write(appOfflineMessage, 0, appOfflineMessage.Length);
1745 * Finish processing request, sync or async
1747 private void FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) {
1748 HttpResponse response = context.Response;
1750 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
1752 SetExecutionTimePerformanceCounter(context);
1754 // Flush in case of no error
1756 // impersonate around PreSendHeaders / PreSendContent
1757 using (new ClientImpersonationContext(context, false)) {
1759 // this sends the actual content in most cases
1760 response.FinalFlushAtTheEndOfRequestProcessing();
1762 catch (Exception eFlush) {
1768 // Report error if any
1770 using (new DisposableHttpContextWrapper(context)) {
1772 // if the custom encoder throws, it might interfere with returning error information
1773 // to the client, so we force use of the default encoder
1774 context.DisableCustomHttpEncoder = true;
1776 if (_appOfflineMessage != null) {
1778 ReportAppOfflineErrorMessage(response, _appOfflineMessage);
1779 response.FinalFlushAtTheEndOfRequestProcessing();
1785 // when application is on UNC share the code below must
1786 // be run while impersonating the token given by IIS
1787 using (new ApplicationImpersonationContext()) {
1790 // try to report error in a way that could possibly throw (a config exception)
1791 response.ReportRuntimeError(e, true /*canThrow*/, false);
1793 catch (Exception eReport) {
1794 // report the config error in a way that would not throw
1795 response.ReportRuntimeError(eReport, false /*canThrow*/, false);
1798 response.FinalFlushAtTheEndOfRequestProcessing();
1807 // Remember that first request is done
1808 _firstRequestCompleted = true;
1811 // In case we reporting HostingInit() error, app domain should not stick around
1812 if (_hostingInitFailed) {
1813 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of HostingInit error");
1814 ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, "HostingInit error");
1817 // Check status code and increment proper counter
1818 // If it's an error status code (i.e. 400 or higher), increment the proper perf counters
1819 int statusCode = response.StatusCode;
1820 UpdatePerfCounters(statusCode);
1822 context.FinishRequestForCachedPathData(statusCode);
1824 // ---- exceptions from EndOfRequest as they will prevent proper request cleanup
1825 // Since the exceptions are not expected here we want to log them
1829 catch (Exception ex) {
1830 WebBaseEvent.RaiseRuntimeError(ex, this);
1833 // Count active requests
1834 HostingEnvironment.DecrementBusyCount();
1835 Interlocked.Decrement(ref _activeRequestCount);
1837 // Schedule more work if some requests are queued
1838 if (_requestQueue != null)
1839 _requestQueue.ScheduleMoreWorkIfNeeded();
1843 // Make sure shutdown happens only once
1846 private bool InitiateShutdownOnce() {
1847 if (_shutdownInProgress)
1851 if (_shutdownInProgress)
1853 _shutdownInProgress = true;
1860 // Shutdown this and restart new app domain
1862 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1863 private void ReleaseResourcesAndUnloadAppDomain(Object state /*not used*/) {
1865 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
1866 "*** ReleaseResourcesAndUnloadAppDomain " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
1867 + ": _appDomainAppId=" + _appDomainAppId);
1869 Debug.Trace("AppDomainFactory", "ReleaseResourcesAndUnloadAppDomain, Id=" + _appDomainAppId
1870 + " DomainId = " + _appDomainId
1871 + " Stack = " + Environment.StackTrace );
1874 PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.APPLICATION_RESTARTS);
1879 // Release all resources
1888 AddAppDomainTraceMessage("before Unload");
1892 AppDomain.Unload(Thread.GetDomain());
1894 catch (CannotUnloadAppDomainException) {
1895 Debug.Assert(false);
1897 catch (Exception e) {
1898 Debug.Trace("AppDomainFactory", "AppDomain.Unload exception: " + e + "; Id=" + _appDomainAppId);
1899 if (!BuildManagerHost.InClientBuildManager) {
1900 // Avoid calling Exception.ToString if we are in the ClientBuildManager (Dev10 bug 824659)
1901 AddAppDomainTraceMessage("Unload Exception: " + e);
1908 private static void SetExecutionTimePerformanceCounter(HttpContext context) {
1909 // Set the Request Execution time perf counter
1910 TimeSpan elapsed = DateTime.UtcNow.Subtract(context.WorkerRequest.GetStartTime());
1911 long milli = elapsed.Ticks / TimeSpan.TicksPerMillisecond;
1913 if (milli > Int32.MaxValue)
1914 milli = Int32.MaxValue;
1916 PerfCounters.SetGlobalCounter(GlobalPerfCounter.REQUEST_EXECUTION_TIME, (int)milli);
1917 PerfCounters.SetCounter(AppPerfCounter.APP_REQUEST_EXEC_TIME, (int)milli);
1920 private static void UpdatePerfCounters(int statusCode) {
1921 if (400 <= statusCode) {
1922 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED);
1923 switch (statusCode) {
1924 case 401: // Not authorized
1925 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_AUTHORIZED);
1927 case 404: // Not found
1928 case 414: // Not found
1929 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);
1934 // If status code is not in the 400-599 range (i.e. 200-299 success or 300-399 redirection),
1935 // count it as a successful request.
1936 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_SUCCEDED);
1940 private void WaitForRequestsToFinish(int waitTimeoutMs) {
1941 DateTime waitLimit = DateTime.UtcNow.AddMilliseconds(waitTimeoutMs);
1944 if (_activeRequestCount == 0 && (_requestQueue == null || _requestQueue.IsEmpty))
1949 // only apply timeout if a managed debugger is not attached
1950 if (!System.Diagnostics.Debugger.IsAttached && DateTime.UtcNow > waitLimit) {
1951 break; // give it up
1957 * Cleanup of all unmananged state
1959 private void Dispose() {
1960 // get shutdown timeout from config
1961 int drainTimeoutSec = HttpRuntimeSection.DefaultShutdownTimeout;
1963 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppLKGConfig().HttpRuntime;
1964 if (runtimeConfig != null) {
1965 drainTimeoutSec = (int)runtimeConfig.ShutdownTimeout.TotalSeconds;
1968 // before aborting compilation give time to drain (new requests are no longer coming at this point)
1969 WaitForRequestsToFinish(drainTimeoutSec * 1000);
1971 // reject remaining queued requests
1972 if (_requestQueue != null)
1973 _requestQueue.Drain();
1975 // By this time all new requests should be directed to a newly created app domain
1976 // But there might be requests that got dispatched to this old app domain but have not reached ProcessRequestInternal yet
1977 // Signal ProcessRequestInternal to reject them immediately without initiating async operations
1978 _disposingHttpRuntime = true;
1981 // give it a little more time to drain
1982 WaitForRequestsToFinish((drainTimeoutSec * 1000) / 6);
1985 // wait for pending async io to complete, prior to aborting requests
1986 // this isn't necessary for IIS 7, where the async sends are always done
1987 // from native code with native buffers
1988 System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.WaitForPendingAsyncIo();
1990 // For IIS7 integrated pipeline, wait until GL_APPLICATION_STOP fires and
1991 // there are no active calls to IndicateCompletion before unloading the AppDomain
1992 if (HttpRuntime.UseIntegratedPipeline) {
1993 PipelineRuntime.WaitForRequestsToDrain();
1996 // wait for all active requests to complete
1997 while (_activeRequestCount != 0) {
2003 // Dispose AppDomainShutdownTimer
2004 DisposeAppDomainShutdownTimer();
2006 // kill all remaining requests (and the timeout timer)
2007 _timeoutManager.Stop();
2008 AppDomainResourcePerfCounters.Stop();
2010 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
2011 // double check for pending async io
2012 System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.WaitForPendingAsyncIo();
2014 // stop sqlcachedependency polling
2015 SqlCacheDependencyManager.Dispose((drainTimeoutSec * 1000) / 2);
2016 #endif // !FEATURE_PAL
2017 // cleanup cache (this ends all sessions)
2018 HealthMonitoringManager.IsCacheDisposed = true; // HMM is the only place internally where we care if the Cache is disposed or not.
2019 if (_cachePublic != null) {
2020 var oCache = HttpRuntime.Cache.GetObjectCache(createIfDoesNotExist: false);
2021 var iCache = HttpRuntime.Cache.GetInternalCache(createIfDoesNotExist: false);
2022 if (oCache != null) {
2025 if (iCache != null) {
2030 // app on end, cleanup app instances
2031 HttpApplicationFactory.EndApplication(); // call app_onEnd
2033 // stop file changes monitor
2036 // stop health monitoring timer
2037 HealthMonitoringManager.Shutdown();
2041 * Async completion of IIS7 pipeline (unlike OnHandlerCompletion, this may fire more than once).
2043 private void OnRequestNotificationCompletion(IAsyncResult ar) {
2045 OnRequestNotificationCompletionHelper(ar);
2047 catch(Exception e) {
2048 ApplicationManager.RecordFatalException(e);
2053 private void OnRequestNotificationCompletionHelper(IAsyncResult ar) {
2054 if (ar.CompletedSynchronously) {
2055 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion: completed synchronously");
2059 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion: completed asynchronously");
2061 RequestNotificationStatus status = RequestNotificationStatus.Continue;
2062 HttpContext context = (HttpContext) ar.AsyncState;
2063 IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
2066 context.ApplicationInstance.EndProcessRequestNotification(ar);
2068 catch (Exception e) {
2069 status = RequestNotificationStatus.FinishRequest;
2070 context.AddError(e);
2073 // RequestContext is set to null if this is the last notification, so we need to save it
2074 // for the call to PostCompletion
2075 IntPtr requestContext = wr.RequestContext;
2077 FinishRequestNotification(wr, context, ref status);
2079 // set the notification context to null since we are exiting this notification
2080 context.NotificationContext = null;
2082 // Indicate completion to IIS, so that it can resume
2083 // request processing on an IIS thread
2084 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion(" + status + ")");
2085 int result = UnsafeIISMethods.MgdPostCompletion(requestContext, status);
2086 Misc.ThrowIfFailedHr(result);
2090 * Async completion of managed pipeline (called at most one time).
2092 private void OnHandlerCompletion(IAsyncResult ar) {
2093 HttpContext context = (HttpContext)ar.AsyncState;
2096 context.AsyncAppHandler.EndProcessRequest(ar);
2098 catch (Exception e) {
2099 context.AddError(e);
2102 // no longer keep AsyncAppHandler poiting to the application
2103 // is only needed to call EndProcessRequest
2104 context.AsyncAppHandler = null;
2107 FinishRequest(context.WorkerRequest, context, context.Error);
2111 * Notification from worker request that it is done writing from buffer
2112 * so that the buffers can be recycled
2114 private void EndOfSendCallback(HttpWorkerRequest wr, Object arg) {
2115 Debug.Trace("PipelineRuntime", "HttpRuntime.EndOfSendCallback");
2116 HttpContext context = (HttpContext)arg;
2117 context.Request.Dispose();
2118 context.Response.Dispose();
2122 * Notification when something in the bin directory changed
2124 private void OnCriticalDirectoryChange(Object sender, FileChangeEvent e) {
2125 // shutdown the app domain
2126 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of bin dir change or directory rename." +
2127 " FileName=" + e.FileName + " Action=" + e.Action);
2129 ApplicationShutdownReason reason = ApplicationShutdownReason.None;
2130 string directoryName = new DirectoryInfo(e.FileName).Name;
2132 string message = FileChangesMonitor.GenerateErrorMessage(e.Action);
2133 message = (message != null) ? message + directoryName : directoryName + " dir change or directory rename";
2135 if (StringUtil.EqualsIgnoreCase(directoryName, CodeDirectoryName)) {
2136 reason = ApplicationShutdownReason.CodeDirChangeOrDirectoryRename;
2138 else if (StringUtil.EqualsIgnoreCase(directoryName, ResourcesDirectoryName)) {
2139 reason = ApplicationShutdownReason.ResourcesDirChangeOrDirectoryRename;
2141 else if (StringUtil.EqualsIgnoreCase(directoryName, BrowsersDirectoryName)) {
2142 reason = ApplicationShutdownReason.BrowsersDirChangeOrDirectoryRename;
2144 else if (StringUtil.EqualsIgnoreCase(directoryName, BinDirectoryName)) {
2145 reason = ApplicationShutdownReason.BinDirChangeOrDirectoryRename;
2148 if (e.Action == FileAction.Added) {
2149 // Make sure HttpRuntime does not ignore the appdomain shutdown if a file is added (VSWhidbey 363481)
2150 HttpRuntime.SetUserForcedShutdown();
2152 Debug.Trace("AppDomainFactorySpecial", "Call SetUserForcedShutdown: FileName=" + e.FileName + "; now=" + DateTime.Now);
2155 ShutdownAppDomain(reason, message);
2159 * Coalesce file change notifications to minimize sharing violations and AppDomain restarts (ASURT 147492)
2161 internal static void CoalesceNotifications() {
2162 int waitChangeNotification = HttpRuntimeSection.DefaultWaitChangeNotification;
2163 int maxWaitChangeNotification = HttpRuntimeSection.DefaultMaxWaitChangeNotification;
2165 HttpRuntimeSection config = RuntimeConfig.GetAppLKGConfig().HttpRuntime;
2166 if (config != null) {
2167 waitChangeNotification = config.WaitChangeNotification;
2168 maxWaitChangeNotification = config.MaxWaitChangeNotification;
2174 if (waitChangeNotification == 0 || maxWaitChangeNotification == 0)
2177 DateTime maxWait = DateTime.UtcNow.AddSeconds(maxWaitChangeNotification);
2178 // Coalesce file change notifications
2180 while (DateTime.UtcNow < maxWait) {
2181 if (DateTime.UtcNow > _theRuntime.LastShutdownAttemptTime.AddSeconds(waitChangeNotification))
2191 // appdomain shutdown eventhandler
2192 internal static event BuildManagerHostUnloadEventHandler AppDomainShutdown;
2194 internal static void OnAppDomainShutdown(BuildManagerHostUnloadEventArgs e) {
2195 if (AppDomainShutdown != null) {
2196 AppDomainShutdown(_theRuntime, e);
2200 internal static void SetUserForcedShutdown() {
2201 _theRuntime._userForcedShutdown = true;
2205 * Shutdown the current app domain
2207 internal static bool ShutdownAppDomain(ApplicationShutdownReason reason, string message) {
2208 return ShutdownAppDomainWithStackTrace(reason, message, null /*stackTrace*/);
2212 * Shutdown the current app domain with a stack trace. This is useful for callers that are running
2213 * on a QUWI callback, and wouldn't provide a meaningful stack trace by default.
2215 internal static bool ShutdownAppDomainWithStackTrace(ApplicationShutdownReason reason, string message, string stackTrace) {
2216 SetShutdownReason(reason, message);
2217 return ShutdownAppDomain(stackTrace);
2220 private static bool ShutdownAppDomain(string stackTrace) {
2222 Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
2223 "*** ShutdownAppDomain " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
2224 + ": _appDomainAppId=" + HttpRuntime.AppDomainAppId);
2226 // Ignore notifications during the processing of the first request (ASURT 100335)
2227 // skip this if LastShutdownAttemptTime has been set
2228 if (_theRuntime.LastShutdownAttemptTime == DateTime.MinValue && !_theRuntime._firstRequestCompleted && !_theRuntime._userForcedShutdown) {
2229 // check the timeout (don't disable notifications forever
2230 int delayTimeoutSec = HttpRuntimeSection.DefaultDelayNotificationTimeout;
2233 RuntimeConfig runtimeConfig = RuntimeConfig.GetAppLKGConfig();
2234 if (runtimeConfig != null) {
2235 HttpRuntimeSection runtimeSection = runtimeConfig.HttpRuntime;
2236 if (runtimeSection != null) {
2237 delayTimeoutSec = (int)runtimeSection.DelayNotificationTimeout.TotalSeconds;
2239 if (DateTime.UtcNow < _theRuntime._firstRequestStartTime.AddSeconds(delayTimeoutSec)) {
2240 Debug.Trace("AppDomainFactory", "ShutdownAppDomain IGNORED (1st request is not done yet), Id = " + AppDomainAppId);
2251 _theRuntime.RaiseShutdownWebEventOnce();
2254 // VSWhidbey 444472: if an exception is thrown, we consume it and continue executing the following code.
2257 // Update last time ShutdownAppDomain was called
2258 _theRuntime.LastShutdownAttemptTime = DateTime.UtcNow;
2260 if (!HostingEnvironment.ShutdownInitiated) {
2261 // This shutdown is not triggered by hosting environment - let it do the job
2262 HostingEnvironment.InitiateShutdownWithoutDemand();
2266 //WOS 1400290: CantUnloadAppDomainException in ISAPI mode, wait until HostingEnvironment.ShutdownThisAppDomainOnce completes
2267 if (HostingEnvironment.ShutdownInProgress) {
2271 // Make sure we don't go through shutdown logic many times
2272 if (!_theRuntime.InitiateShutdownOnce())
2275 Debug.Trace("AppDomainFactory", "ShutdownAppDomain, Id = " + AppDomainAppId + ", ShutdownInProgress=" + ShutdownInProgress
2276 + ", ShutdownMessage=" + _theRuntime._shutDownMessage);
2278 if (String.IsNullOrEmpty(stackTrace) && !BuildManagerHost.InClientBuildManager) {
2279 // Avoid calling Environment.StackTrace if we are in the ClientBuildManager (Dev10 bug 824659)
2281 // Instrument to be able to see what's causing a shutdown
2282 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
2284 _theRuntime._shutDownStack = Environment.StackTrace;
2287 CodeAccessPermission.RevertAssert();
2291 _theRuntime._shutDownStack = stackTrace;
2294 // Notify when appdomain is about to shutdown.
2295 OnAppDomainShutdown(new BuildManagerHostUnloadEventArgs(_theRuntime._shutdownReason));
2297 // unload app domain from another CLR thread
2298 ThreadPool.QueueUserWorkItem(_theRuntime._appDomainUnloadallback);
2303 internal static void RecoverFromUnexceptedAppDomainUnload() {
2304 if (_theRuntime._shutdownInProgress)
2307 // someone unloaded app domain directly - tell unmanaged code
2308 Debug.Trace("AppDomainFactory", "Unexpected AppDomainUnload");
2309 _theRuntime._shutdownInProgress = true;
2311 // tell unmanaged code not to dispatch requests to this app domain
2313 ISAPIRuntime.RemoveThisAppDomainFromUnmanagedTable();
2314 PipelineRuntime.RemoveThisAppDomainFromUnmanagedTable();
2315 AddAppDomainTraceMessage("AppDomainRestart");
2318 // release all resources
2319 _theRuntime.Dispose();
2324 * Notification when app-level Config changed
2326 internal static void OnConfigChange(String message) {
2327 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of config change");
2328 ShutdownAppDomain(ApplicationShutdownReason.ConfigurationChange, (message != null) ? message : "CONFIG change");
2331 // Intrumentation to remember the overwhelming file change
2332 internal static void SetShutdownReason(ApplicationShutdownReason reason, String message) {
2333 if (_theRuntime._shutdownReason == ApplicationShutdownReason.None) {
2334 _theRuntime._shutdownReason = reason;
2337 SetShutdownMessage(message);
2340 internal static void SetShutdownMessage(String message) {
2341 if (message != null) {
2342 if (_theRuntime._shutDownMessage == null)
2343 _theRuntime._shutDownMessage = message;
2345 _theRuntime._shutDownMessage += "\r\n" + message;
2350 // public method is on HostingEnvironment
2351 internal static ApplicationShutdownReason ShutdownReason {
2352 get { return _theRuntime._shutdownReason; }
2356 // public static APIs
2360 * Process one request
2364 /// <para><SPAN>The method that drives
2365 /// all ASP.NET web processing execution.</SPAN></para>
2367 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
2368 public static void ProcessRequest(HttpWorkerRequest wr) {
2370 throw new ArgumentNullException("wr");
2372 if (HttpRuntime.UseIntegratedPipeline) {
2373 throw new PlatformNotSupportedException(SR.GetString(SR.Method_Not_Supported_By_Iis_Integrated_Mode, "HttpRuntime.ProcessRequest"));
2376 ProcessRequestNoDemand(wr);
2380 internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) {
2381 RequestQueue rq = _theRuntime._requestQueue;
2383 wr.UpdateInitialCounters();
2385 if (rq != null) // could be null before first request
2386 wr = rq.GetRequestToExecute(wr);
2389 CalculateWaitTimeAndUpdatePerfCounter(wr);
2390 wr.ResetStartTime();
2391 ProcessRequestNow(wr);
2396 private static void CalculateWaitTimeAndUpdatePerfCounter(HttpWorkerRequest wr) {
2397 DateTime begin = wr.GetStartTime();
2399 TimeSpan elapsed = DateTime.UtcNow.Subtract(begin);
2400 long milli = elapsed.Ticks / TimeSpan.TicksPerMillisecond;
2402 if (milli > Int32.MaxValue)
2403 milli = Int32.MaxValue;
2405 PerfCounters.SetGlobalCounter(GlobalPerfCounter.REQUEST_WAIT_TIME, (int)milli);
2406 PerfCounters.SetCounter(AppPerfCounter.APP_REQUEST_WAIT_TIME, (int)milli);
2409 internal static void ProcessRequestNow(HttpWorkerRequest wr) {
2410 _theRuntime.ProcessRequestInternal(wr);
2413 internal static void RejectRequestNow(HttpWorkerRequest wr, bool silent) {
2414 _theRuntime.RejectRequestInternal(wr, silent);
2419 /// <para>Removes all items from the cache and shuts down the runtime.</para>
2421 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
2422 public static void Close() {
2423 Debug.Trace("AppDomainFactory", "HttpRuntime.Close, ShutdownInProgress=" + ShutdownInProgress);
2424 if (_theRuntime.InitiateShutdownOnce()) {
2425 SetShutdownReason(ApplicationShutdownReason.HttpRuntimeClose, "HttpRuntime.Close is called");
2427 if (HostingEnvironment.IsHosted) {
2428 // go throw initiate shutdown for hosted scenarios
2429 HostingEnvironment.InitiateShutdownWithoutDemand();
2432 _theRuntime.Dispose();
2439 /// <para>Unloads the current app domain.</para>
2441 public static void UnloadAppDomain() {
2442 _theRuntime._userForcedShutdown = true;
2443 ShutdownAppDomain(ApplicationShutdownReason.UnloadAppDomainCalled, "User code called UnloadAppDomain");
2446 private DateTime LastShutdownAttemptTime {
2450 dt = _lastShutdownAttemptTime;
2456 _lastShutdownAttemptTime = value;
2461 internal static Profiler Profile {
2463 return _theRuntime._profiler;
2467 internal static bool IsTrustLevelInitialized {
2469 return !HostingEnvironment.IsHosted || TrustLevel != null;
2473 internal static NamedPermissionSet NamedPermissionSet {
2475 // Make sure we have already initialized the trust level
2479 return _theRuntime._namedPermissionSet;
2483 internal static PolicyLevel PolicyLevel {
2485 return _theRuntime._policyLevel;
2489 internal static string HostSecurityPolicyResolverType {
2491 return _theRuntime._hostSecurityPolicyResolverType;
2495 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Unrestricted)]
2496 public static NamedPermissionSet GetNamedPermissionSet() {
2497 NamedPermissionSet namedPermissionSet = _theRuntime._namedPermissionSet;
2498 if (namedPermissionSet == null) {
2502 return new NamedPermissionSet(namedPermissionSet);
2506 internal static bool IsFullTrust {
2508 // Make sure we have already initialized the trust level
2509 Debug.Assert(IsTrustLevelInitialized);
2511 return (_theRuntime._namedPermissionSet == null);
2516 * Check that the current trust level allows access to a virtual path. Throw if it doesn't,
2518 internal static void CheckVirtualFilePermission(string virtualPath) {
2519 string physicalPath = HostingEnvironment.MapPath(virtualPath);
2520 CheckFilePermission(physicalPath);
2524 * Check that the current trust level allows access to a path. Throw if it doesn't,
2526 internal static void CheckFilePermission(string path) {
2527 CheckFilePermission(path, false);
2530 internal static void CheckFilePermission(string path, bool writePermissions) {
2531 if (!HasFilePermission(path, writePermissions)) {
2532 throw new HttpException(SR.GetString(SR.Access_denied_to_path, GetSafePath(path)));
2536 internal static bool HasFilePermission(string path) {
2537 return HasFilePermission(path, false);
2540 internal static bool HasFilePermission(string path, bool writePermissions) {
2541 // WOS #1523618: need to skip this check for HttpResponse.ReportRuntimeError when reporting an
2542 // InitializationException (e.g., necessary to display line info for ConfigurationException).
2544 if (TrustLevel == null && InitializationException != null) {
2548 // Make sure we have already initialized the trust level
2549 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted, "TrustLevel != null || !HostingEnvironment.IsHosted");
2551 // If we don't have a NamedPermissionSet, we're in full trust
2552 if (NamedPermissionSet == null)
2555 bool fAccess = false;
2557 // Check that the user has permission to the path
2558 IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(FileIOPermission));
2559 if (allowedPermission != null) {
2560 IPermission askedPermission = null;
2562 if (!writePermissions)
2563 askedPermission = new FileIOPermission(FileIOPermissionAccess.Read, path);
2565 askedPermission = new FileIOPermission(FileIOPermissionAccess.AllAccess, path);
2568 // This could happen if the path is not absolute
2571 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2577 internal static bool HasWebPermission(Uri uri) {
2579 // Make sure we have already initialized the trust level
2580 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2582 // If we don't have a NamedPermissionSet, we're in full trust
2583 if (NamedPermissionSet == null)
2586 bool fAccess = false;
2588 // Check that the user has permission to the URI
2589 IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(WebPermission));
2590 if (allowedPermission != null) {
2591 IPermission askedPermission = null;
2593 askedPermission = new WebPermission(NetworkAccess.Connect, uri.ToString());
2598 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2604 internal static bool HasDbPermission(DbProviderFactory factory) {
2606 // Make sure we have already initialized the trust level
2607 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2609 // If we don't have a NamedPermissionSet, we're in full trust
2610 if (NamedPermissionSet == null)
2613 bool fAccess = false;
2615 // Check that the user has permission to the provider
2616 CodeAccessPermission askedPermission = factory.CreatePermission(PermissionState.Unrestricted);
2617 if (askedPermission != null) {
2618 IPermission allowedPermission = NamedPermissionSet.GetPermission(askedPermission.GetType());
2619 if (allowedPermission != null) {
2620 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2627 internal static bool HasPathDiscoveryPermission(string path) {
2628 // WOS #1523618: need to skip this check for HttpResponse.ReportRuntimeError when reporting an
2629 // InitializationException (e.g., necessary to display line info for ConfigurationException).
2631 if (TrustLevel == null && InitializationException != null) {
2635 // Make sure we have already initialized the trust level
2636 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2638 // If we don't have a NamedPermissionSet, we're in full trust
2639 if (NamedPermissionSet == null)
2642 bool fAccess = false;
2644 // Check that the user has permission to the path
2645 IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(FileIOPermission));
2646 if (allowedPermission != null) {
2647 IPermission askedPermission = new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path);
2648 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2655 internal static bool HasAppPathDiscoveryPermission() {
2656 return HasPathDiscoveryPermission(HttpRuntime.AppDomainAppPathInternal);
2659 internal static string GetSafePath(string path) {
2660 if (String.IsNullOrEmpty(path))
2664 if (HasPathDiscoveryPermission(path)) // could throw on bad filenames
2670 return Path.GetFileName(path);
2674 * Check that the current trust level allows Unmanaged access
2676 internal static bool HasUnmanagedPermission() {
2678 // Make sure we have already initialized the trust level
2679 Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2681 // If we don't have a NamedPermissionSet, we're in full trust
2682 if (NamedPermissionSet == null)
2685 SecurityPermission securityPermission = (SecurityPermission)NamedPermissionSet.GetPermission(
2686 typeof(SecurityPermission));
2687 if (securityPermission == null)
2690 return (securityPermission.Flags & SecurityPermissionFlag.UnmanagedCode) != 0;
2693 internal static bool HasAspNetHostingPermission(AspNetHostingPermissionLevel level) {
2695 // Make sure we have already initialized the trust level
2700 // If we don't have a NamedPermissionSet, we're in full trust
2701 if (NamedPermissionSet == null)
2704 AspNetHostingPermission permission = (AspNetHostingPermission)NamedPermissionSet.GetPermission(
2705 typeof(AspNetHostingPermission));
2706 if (permission == null)
2709 return (permission.Level >= level);
2712 internal static void CheckAspNetHostingPermission(AspNetHostingPermissionLevel level, String errorMessageId) {
2713 if (!HasAspNetHostingPermission(level)) {
2714 throw new HttpException(SR.GetString(errorMessageId));
2718 // If we're not in full trust, fail if the passed in type doesn't have the APTCA bit
2719 internal static void FailIfNoAPTCABit(Type t, ElementInformation elemInfo, string propertyName) {
2721 if (!IsTypeAllowedInConfig(t)) {
2722 if (null != elemInfo) {
2723 PropertyInformation propInfo = elemInfo.Properties[propertyName];
2725 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName),
2726 propInfo.Source, propInfo.LineNumber);
2729 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName));
2734 // If we're not in full trust, fail if the passed in type doesn't have the APTCA bit
2735 internal static void FailIfNoAPTCABit(Type t, XmlNode node) {
2737 if (!IsTypeAllowedInConfig(t)) {
2738 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName),
2743 private static bool HasAPTCABit(Assembly assembly) {
2744 return assembly.IsDefined(typeof(AllowPartiallyTrustedCallersAttribute), inherit: false);
2747 // Check if the type is allowed to be used in config by checking the APTCA bit
2748 internal static bool IsTypeAllowedInConfig(Type t) {
2750 // Allow everything in full trust
2751 if (HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted))
2754 return IsTypeAccessibleFromPartialTrust(t);
2757 internal static bool IsTypeAccessibleFromPartialTrust(Type t) {
2758 Assembly assembly = t.Assembly;
2760 if (assembly.SecurityRuleSet == SecurityRuleSet.Level1) {
2761 // Level 1 CAS uses transparency as an auditing mechanism rather than an enforcement mechanism, so we can't
2762 // perform a transparency check. Instead, allow the call to go through if:
2763 // (a) the referenced assembly is partially trusted, hence it cannot do anything dangerous; or
2764 // (b) the assembly is fully trusted and has APTCA.
2765 return (!assembly.IsFullyTrusted || HasAPTCABit(assembly));
2769 // Some GACed assemblies register critical modules / handlers. We can't break these scenarios for .NET 4.5, but we should
2770 // remove this APTCA check when we fix DevDiv #85358 and use only the transparency check defined below.
2771 if (HasAPTCABit(assembly)) {
2774 // ** END TEMPORARY **
2776 // Level 2 CAS uses transparency as an enforcement mechanism, so we can perform a transparency check.
2777 // Transparent and SafeCritical types are safe to use from partial trust code.
2778 return (t.IsSecurityTransparent || t.IsSecuritySafeCritical);
2782 internal static FileChangesMonitor FileChangesMonitor {
2783 get { return _theRuntime._fcm; }
2786 internal static RequestTimeoutManager RequestTimeoutManager {
2787 get { return _theRuntime._timeoutManager; }
2792 /// <para>Provides access to the cache.</para>
2794 public static Cache Cache {
2797 if (HttpRuntime.AspInstallDirectoryInternal == null) {
2798 throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2801 Cache cachePublic = _theRuntime._cachePublic;
2802 if (cachePublic == null) {
2803 lock (_theRuntime) {
2804 cachePublic = _theRuntime._cachePublic;
2805 if (cachePublic == null) {
2806 // Create the CACHE object
2807 cachePublic = new Caching.Cache(0);
2808 _theRuntime._cachePublic = cachePublic;
2818 /// <para>[To be supplied.]</para>
2820 public static string AspInstallDirectory {
2822 String path = AspInstallDirectoryInternal;
2825 throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2828 InternalSecurityPermissions.PathDiscovery(path).Demand();
2833 internal static string AspInstallDirectoryInternal {
2834 get { return s_installDirectory; }
2838 // Return the client script virtual path, e.g. "/aspnet_client/system_web/2_0_50217"
2840 public static string AspClientScriptVirtualPath {
2842 if (_theRuntime._clientScriptVirtualPath == null) {
2843 string aspNetVersion = VersionInfo.SystemWebVersion;
2844 string clientScriptVirtualPath = AspNetClientFilesParentVirtualPath + aspNetVersion.Substring(0, aspNetVersion.LastIndexOf('.')).Replace('.', '_');
2846 _theRuntime._clientScriptVirtualPath = clientScriptVirtualPath;
2849 return _theRuntime._clientScriptVirtualPath;
2853 public static string AspClientScriptPhysicalPath {
2855 String path = AspClientScriptPhysicalPathInternal;
2858 throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2866 // Return the client script physical path, e.g. @"c:\windows\microsoft.net\framework\v2.0.50217.0\asp.netclientfiles"
2868 internal static string AspClientScriptPhysicalPathInternal {
2870 if (_theRuntime._clientScriptPhysicalPath == null) {
2871 string clientScriptPhysicalPath = System.IO.Path.Combine(AspInstallDirectoryInternal, AspNetClientFilesSubDirectory);
2873 _theRuntime._clientScriptPhysicalPath = clientScriptPhysicalPath;
2876 return _theRuntime._clientScriptPhysicalPath;
2882 /// <para>[To be supplied.]</para>
2884 public static string ClrInstallDirectory {
2886 String path = ClrInstallDirectoryInternal;
2887 InternalSecurityPermissions.PathDiscovery(path).Demand();
2892 internal static string ClrInstallDirectoryInternal {
2893 get { return HttpConfigurationSystem.MsCorLibDirectory; }
2899 /// <para>[To be supplied.]</para>
2901 public static string MachineConfigurationDirectory {
2903 String path = MachineConfigurationDirectoryInternal;
2904 InternalSecurityPermissions.PathDiscovery(path).Demand();
2909 internal static string MachineConfigurationDirectoryInternal {
2910 get { return HttpConfigurationSystem.MachineConfigurationDirectory; }
2913 internal static bool IsEngineLoaded {
2914 get { return s_isEngineLoaded; }
2919 // Static app domain related properties
2924 /// <para>[To be supplied.]</para>
2926 public static String CodegenDir {
2928 String path = CodegenDirInternal;
2929 InternalSecurityPermissions.PathDiscovery(path).Demand();
2934 internal static string CodegenDirInternal {
2935 get { return _theRuntime._codegenDir; }
2938 internal static string TempDirInternal {
2939 get { return _theRuntime._tempDir; }
2944 /// <para>[To be supplied.]</para>
2946 public static String AppDomainAppId {
2948 return _theRuntime._appDomainAppId;
2952 internal static bool IsAspNetAppDomain {
2953 get { return AppDomainAppId != null; }
2959 /// <para>[To be supplied.]</para>
2961 public static String AppDomainAppPath {
2963 InternalSecurityPermissions.AppPathDiscovery.Demand();
2964 return AppDomainAppPathInternal;
2968 internal static string AppDomainAppPathInternal {
2969 get { return _theRuntime._appDomainAppPath; }
2974 /// <para>[To be supplied.]</para>
2976 public static String AppDomainAppVirtualPath {
2978 return VirtualPath.GetVirtualPathStringNoTrailingSlash(_theRuntime._appDomainAppVPath);
2982 // Save as AppDomainAppVirtualPath, but includes the trailng slash. We can't change
2983 // AppDomainAppVirtualPath since it's public.
2984 internal static String AppDomainAppVirtualPathString {
2986 return VirtualPath.GetVirtualPathString(_theRuntime._appDomainAppVPath);
2990 internal static VirtualPath AppDomainAppVirtualPathObject {
2992 return _theRuntime._appDomainAppVPath;
2996 internal static bool IsPathWithinAppRoot(String path) {
2997 if (AppDomainIdInternal == null)
2998 return true; // app domain not initialized
3000 return UrlPath.IsEqualOrSubpath(AppDomainAppVirtualPathString, path);
3005 /// <para>[To be supplied.]</para>
3007 public static String AppDomainId {
3008 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
3010 return AppDomainIdInternal;
3014 internal static string AppDomainIdInternal {
3015 get { return _theRuntime._appDomainId; }
3021 /// <para>[To be supplied.]</para>
3023 public static String BinDirectory {
3025 String path = BinDirectoryInternal;
3026 InternalSecurityPermissions.PathDiscovery(path).Demand();
3031 internal static string BinDirectoryInternal {
3032 get { return Path.Combine(_theRuntime._appDomainAppPath, BinDirectoryName) + Path.DirectorySeparatorChar; }
3036 internal static VirtualPath CodeDirectoryVirtualPath {
3037 get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(CodeDirectoryName); }
3040 internal static VirtualPath ResourcesDirectoryVirtualPath {
3041 get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(ResourcesDirectoryName); }
3044 internal static VirtualPath WebRefDirectoryVirtualPath {
3045 get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(WebRefDirectoryName); }
3050 /// <para>[To be supplied.]</para>
3052 public static bool IsOnUNCShare {
3053 [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
3055 return IsOnUNCShareInternal;
3059 internal static bool IsOnUNCShareInternal {
3060 get { return _theRuntime._isOnUNCShare; }
3065 // Static helper to retrieve app domain values
3068 private static String GetAppDomainString(String key) {
3069 Object x = Thread.GetDomain().GetData(key);
3074 internal static void AddAppDomainTraceMessage(String message) {
3075 const String appDomainTraceKey = "ASP.NET Domain Trace";
3076 AppDomain d = Thread.GetDomain();
3077 String m = d.GetData(appDomainTraceKey) as String;
3078 d.SetData(appDomainTraceKey, (m != null) ? m + " ... " + message : message);
3081 // Gets the version of the ASP.NET framework the current web applications is targeting.
3082 // This property is normally set via the <httpRuntime> element's "targetFramework"
3083 // attribute. The property is not guaranteed to return a correct value if the current
3084 // AppDomain is not an ASP.NET web application AppDomain.
3085 public static Version TargetFramework {
3087 return BinaryCompatibility.Current.TargetFramework;
3096 internal static bool DebuggingEnabled {
3097 get { return _theRuntime._debuggingEnabled; }
3100 internal static bool ConfigInited {
3101 get { return _theRuntime._configInited; }
3104 internal static bool FusionInited {
3105 get { return _theRuntime._fusionInited; }
3108 internal static bool ApartmentThreading {
3109 get { return _theRuntime._apartmentThreading; }
3112 internal static bool ShutdownInProgress {
3113 get { return _theRuntime._shutdownInProgress; }
3116 internal static string TrustLevel {
3117 get { return _theRuntime._trustLevel; }
3120 internal static string WpUserId {
3121 get { return _theRuntime._wpUserId; }
3125 private void SetTrustLevel(TrustSection trustSection, SecurityPolicySection securityPolicySection) {
3126 // Use a temporary variable, since we use the field as a signal that the trust has really
3127 // been set, which is not the case until later in this method.
3128 string trustLevel = trustSection.Level;
3130 if (trustSection.Level == "Full") {
3131 _trustLevel = trustLevel;
3135 if (securityPolicySection == null || securityPolicySection.TrustLevels[trustSection.Level] == null) {
3136 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level), String.Empty, 0);
3137 // Do not give out configuration information since we don't know what trust level we are
3138 // supposed to be running at. If the information below is added to the error it might expose
3139 // part of the config file that the users does not have permissions to see. VS261145
3140 // ,trustSection.ElementInformation.Properties["level"].Source,
3141 // trustSection.ElementInformation.Properties["level"].LineNumber);
3144 if (trustSection.Level == "Minimal" || trustSection.Level == "Low" ||
3145 trustSection.Level == "Medium" || trustSection.Level == "High") {
3146 file = (String)securityPolicySection.TrustLevels[trustSection.Level].LegacyPolicyFileExpanded;
3149 file = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
3151 if (file == null || !FileUtil.FileExists(file)) {
3152 //if HttpContext.Current.IsCustomErrorEnabled
3153 throw new HttpException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
3155 // throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level),
3156 // trustSection.Filename, trustSection.LineNumber);
3159 bool foundGacToken = false;
3160 #pragma warning disable 618
3161 PolicyLevel policyLevel = CreatePolicyLevel(file, AppDomainAppPathInternal, CodegenDirInternal, trustSection.OriginUrl, out foundGacToken);
3163 // see if the policy file contained a v1.x UrlMembershipCondition containing
3164 // a GAC token. If so, let's upgrade it by adding a code group granting
3165 // full trust to code from the GAC
3166 if (foundGacToken) {
3167 // walk the code groups at the app domain level and look for one that grants
3168 // access to the GAC with an UrlMembershipCondition.
3169 CodeGroup rootGroup = policyLevel.RootCodeGroup;
3170 bool foundGacCondition = false;
3171 foreach (CodeGroup childGroup in rootGroup.Children) {
3172 if (childGroup.MembershipCondition is GacMembershipCondition) {
3173 foundGacCondition = true;
3175 // if we found the GAC token and also have the GacMembershipCondition
3176 // the policy file needs to be upgraded to just include the GacMembershipCondition
3177 Debug.Assert(!foundGacCondition);
3182 // add one as a child of the toplevel group after
3183 // some sanity checking to make sure it's an ASP.NET policy file
3184 // which always begins with a FirstMatchCodeGroup granting nothing
3185 // this might not upgrade some custom policy files
3186 if (!foundGacCondition) {
3187 if (rootGroup is FirstMatchCodeGroup) {
3188 FirstMatchCodeGroup firstMatch = (FirstMatchCodeGroup)rootGroup;
3189 if (firstMatch.MembershipCondition is AllMembershipCondition &&
3190 firstMatch.PermissionSetName == "Nothing") {
3191 PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
3193 CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(),
3194 new PolicyStatement(fullTrust));
3197 // now, walk the current groups and insert our new group
3198 // immediately before the old Gac group
3199 // we'll need to use heuristics for this:
3200 // it will be an UrlMembershipCondition group with full trust
3201 CodeGroup newRoot = new FirstMatchCodeGroup(rootGroup.MembershipCondition, rootGroup.PolicyStatement);
3202 foreach (CodeGroup childGroup in rootGroup.Children) {
3204 // is this the target old $Gac$ group?
3205 // insert our new GacMembershipCondition group ahead of it
3206 if ((childGroup is UnionCodeGroup) &&
3207 (childGroup.MembershipCondition is UrlMembershipCondition) &&
3208 childGroup.PolicyStatement.PermissionSet.IsUnrestricted()) {
3209 if (null != gacGroup) {
3210 newRoot.AddChild(gacGroup);
3215 // append this group to the root group
3216 // AddChild itself does a deep Copy to get any
3217 // child groups so we don't need one here
3218 newRoot.AddChild(childGroup);
3221 policyLevel.RootCodeGroup = newRoot;
3222 //Debug.Trace("internal", "PolicyLevel: " + policyLevel.ToXml());
3226 #pragma warning restore 618
3230 #pragma warning disable 618
3231 AppDomain.CurrentDomain.SetAppDomainPolicy(policyLevel);
3232 _namedPermissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
3233 #pragma warning restore 618
3235 _trustLevel = trustLevel;
3237 _fcm.StartMonitoringFile(file, new FileChangeEventHandler(this.OnSecurityPolicyFileChange));
3240 #pragma warning disable 618
3241 private static PolicyLevel CreatePolicyLevel(String configFile, String appDir, String binDir, String strOriginUrl, out bool foundGacToken) {
3242 // Read in the config file to a string.
3243 FileStream file = new FileStream(configFile, FileMode.Open, FileAccess.Read);
3244 StreamReader reader = new StreamReader(file, Encoding.UTF8);
3245 String strFileData = reader.ReadToEnd();
3249 appDir = FileUtil.RemoveTrailingDirectoryBackSlash(appDir);
3250 binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir);
3252 strFileData = strFileData.Replace("$AppDir$", appDir);
3253 strFileData = strFileData.Replace("$AppDirUrl$", MakeFileUrl(appDir));
3254 strFileData = strFileData.Replace("$CodeGen$", MakeFileUrl(binDir));
3255 if (strOriginUrl == null)
3256 strOriginUrl = String.Empty;
3257 strFileData = strFileData.Replace("$OriginHost$", strOriginUrl);
3259 // see if the file contains a GAC token
3260 // if so, do the replacement and record the
3261 // fact so that we later add a GacMembershipCondition
3262 // codegroup to the PolicyLevel
3263 int ndx = strFileData.IndexOf("$Gac$", StringComparison.Ordinal);
3265 string gacLocation = GetGacLocation();
3266 if (gacLocation != null)
3267 gacLocation = MakeFileUrl(gacLocation);
3268 if (gacLocation == null)
3269 gacLocation = String.Empty;
3271 strFileData = strFileData.Replace("$Gac$", gacLocation);
3272 foundGacToken = true;
3275 foundGacToken = false;
3278 return SecurityManager.LoadPolicyLevelFromString(strFileData, PolicyLevelType.AppDomain);
3280 #pragma warning restore 618
3282 private void SetTrustParameters(TrustSection trustSection, SecurityPolicySection securityPolicySection, PolicyLevel policyLevel) {
3283 _trustLevel = trustSection.Level;
3284 if (_trustLevel != "Full") {
3285 // if we are in partial trust, HostingEnvironment should init HttpRuntime with a non-null PolicyLevel object
3286 Debug.Assert(policyLevel != null);
3288 _namedPermissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
3289 _policyLevel = policyLevel;
3290 _hostSecurityPolicyResolverType = trustSection.HostSecurityPolicyResolverType;
3291 String file = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
3292 _fcm.StartMonitoringFile(file, new FileChangeEventHandler(this.OnSecurityPolicyFileChange));
3297 * Notification when something in the code-access security policy file changed
3299 private void OnSecurityPolicyFileChange(Object sender, FileChangeEvent e) {
3300 // shutdown the app domain
3301 Debug.Trace("AppDomainFactory", "Shutting down appdomain because code-access security policy file changed");
3302 string message = FileChangesMonitor.GenerateErrorMessage(e.Action, e.FileName);
3303 if (message == null) {
3304 message = "Change in code-access security policy file";
3306 ShutdownAppDomain(ApplicationShutdownReason.ChangeInSecurityPolicyFile,
3311 // notification when app_offline.htm file changed or created
3312 private void OnAppOfflineFileChange(Object sender, FileChangeEvent e) {
3313 // shutdown the app domain
3314 Debug.Trace("AppOffline", AppOfflineFileName + " changed - shutting down the app domain");
3315 Debug.Trace("AppDomainFactory", "Shutting down appdomain because " + AppOfflineFileName + " file changed");
3316 // WOS 1948399: set _userForcedShutdown to avoid DelayNotificationTimeout, since first request has not completed yet in integrated mode;
3317 SetUserForcedShutdown();
3318 string message = FileChangesMonitor.GenerateErrorMessage(e.Action, AppOfflineFileName);
3319 if (message == null) {
3320 message = "Change in " + AppOfflineFileName;
3322 ShutdownAppDomain(ApplicationShutdownReason.ConfigurationChange, message);
3325 internal static String MakeFileUrl(String path) {
3326 Uri uri = new Uri(path);
3327 return uri.ToString();
3330 internal static String GetGacLocation() {
3332 StringBuilder buf = new StringBuilder(262);
3337 if (UnsafeNativeMethods.GetCachePath(2, buf, ref iSize) >= 0)
3338 return buf.ToString();
3339 throw new HttpException(SR.GetString(SR.GetGacLocaltion_failed));
3344 * Remove from metabase all read/write/browse permission from certain subdirs
3347 internal static void RestrictIISFolders(HttpContext context) {
3350 HttpWorkerRequest wr = context.WorkerRequest;
3352 Debug.Assert(AppDomainAppId != null);
3354 // Don't do it if we are not running on IIS
3355 if (wr == null || !(wr is System.Web.Hosting.ISAPIWorkerRequest)) {
3359 // Do it only for IIS 5
3360 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
3361 if (!(wr is System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6))
3362 #endif // !FEATURE_PAL
3365 byte[] bufout = new byte[1]; // Just to keep EcbCallISAPI happy
3367 bufin = BitConverter.GetBytes(UnsafeNativeMethods.RESTRICT_BIN);
3368 ret = context.CallISAPI(UnsafeNativeMethods.CallISAPIFunc.RestrictIISFolders, bufin, bufout);
3370 // Cannot pass back any HR from inetinfo.exe because CSyncPipeManager::GetDataFromIIS
3371 // does not support passing back any value when there is an error.
3372 Debug.Trace("RestrictIISFolders", "Cannot restrict folder access for '" + AppDomainAppId + "'.");
3378 // Helper to create instances (public vs. internal/private ctors, see 89781)
3381 internal static Object CreateNonPublicInstance(Type type) {
3382 return CreateNonPublicInstance(type, null);
3385 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3386 internal static Object CreateNonPublicInstance(Type type, Object[] args) {
3387 return Activator.CreateInstance(
3389 BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
3395 internal static Object CreatePublicInstance(Type type) {
3396 return Activator.CreateInstance(type);
3399 #if !DONTUSEFACTORYGENERATOR
3400 // Cache instances of IWebObjectFactory for each Type, which allow us
3401 // to instantiate the objects very efficiently, compared to calling
3402 // Activator.CreateInstance on every call.
3403 private static FactoryGenerator s_factoryGenerator;
3404 private static Hashtable s_factoryCache;
3405 private static bool s_initializedFactory;
3406 private static object s_factoryLock = new Object();
3408 #endif // DONTUSEFACTORYGENERATOR
3411 * Faster implementation of CreatePublicInstance. It generates bits of IL
3412 * on the fly to achieve the improve performance. this should only be used
3413 * in cases where the number of different types to be created is well bounded.
3414 * Otherwise, we would create too much IL, which can bloat the process.
3416 internal static Object FastCreatePublicInstance(Type type) {
3418 #if DONTUSEFACTORYGENERATOR
3419 return CreatePublicInstance(type);
3422 // Only use the factory logic if the assembly is in the GAC, to avoid getting
3423 // assembly conflicts (VSWhidbey 405086)
3424 if (!type.Assembly.GlobalAssemblyCache) {
3425 return CreatePublicInstance(type);
3428 // Create the factory generator on demand
3429 if (!s_initializedFactory) {
3431 // Devdiv 90810 - Synchronize to avoid race condition
3432 lock (s_factoryLock) {
3433 if (!s_initializedFactory) {
3434 s_factoryGenerator = new FactoryGenerator();
3436 // Create the factory cache
3437 s_factoryCache = Hashtable.Synchronized(new Hashtable());
3439 s_initializedFactory = true;
3444 // First, check if it's cached
3445 IWebObjectFactory factory = (IWebObjectFactory)s_factoryCache[type];
3447 if (factory == null) {
3449 Debug.Trace("FastCreatePublicInstance", "Creating generator for type " + type.FullName);
3451 // Create the object factory
3452 factory = s_factoryGenerator.CreateFactory(type);
3454 // Cache the factory
3455 s_factoryCache[type] = factory;
3458 return factory.CreateInstance();
3459 #endif // DONTUSEFACTORYGENERATOR
3462 internal static Object CreatePublicInstance(Type type, Object[] args) {
3464 return Activator.CreateInstance(type);
3466 return Activator.CreateInstance(type, args);
3469 static string GetCurrentUserName() {
3471 return WindowsIdentity.GetCurrent().Name;
3478 void RaiseShutdownWebEventOnce() {
3479 if (!_shutdownWebEventRaised) {
3481 if (!_shutdownWebEventRaised) {
3483 WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationShutdown,
3484 WebApplicationLifetimeEvent.DetailCodeFromShutdownReason(ShutdownReason));
3486 _shutdownWebEventRaised = true;
3492 private static string _DefaultPhysicalPathOnMapPathFailure;
3493 private void RelaxMapPathIfRequired() {
3495 RuntimeConfig config = RuntimeConfig.GetAppConfig();
3496 if (config != null && config.HttpRuntime != null && config.HttpRuntime.RelaxedUrlToFileSystemMapping) {
3497 _DefaultPhysicalPathOnMapPathFailure = Path.Combine(_appDomainAppPath, "NOT_A_VALID_FILESYSTEM_PATH");
3501 internal static bool IsMapPathRelaxed {
3503 return _DefaultPhysicalPathOnMapPathFailure != null;
3506 internal static string GetRelaxedMapPathResult(string originalResult) {
3507 if (!IsMapPathRelaxed) // Feature not enabled?
3508 return originalResult;
3510 if (originalResult == null) // null is never valid: Return the hard coded default physical path
3511 return _DefaultPhysicalPathOnMapPathFailure;
3513 // Does it contain an invalid file-path char?
3514 if (originalResult.IndexOfAny(s_InvalidPhysicalPathChars) >= 0)
3515 return _DefaultPhysicalPathOnMapPathFailure;
3517 // Final check: do the full check to ensure it is valid
3520 if (FileUtil.IsSuspiciousPhysicalPath(originalResult, out pathTooLong) || pathTooLong)
3521 return _DefaultPhysicalPathOnMapPathFailure;
3523 return _DefaultPhysicalPathOnMapPathFailure;
3527 return originalResult;
3532 public enum ApplicationShutdownReason {
3536 HostingEnvironment = 1,
3538 ChangeInGlobalAsax = 2,
3540 ConfigurationChange = 3,
3542 UnloadAppDomainCalled = 4,
3544 ChangeInSecurityPolicyFile = 5,
3546 BinDirChangeOrDirectoryRename = 6,
3548 BrowsersDirChangeOrDirectoryRename = 7,
3550 CodeDirChangeOrDirectoryRename = 8,
3552 ResourcesDirChangeOrDirectoryRename = 9,
3556 PhysicalApplicationPathChanged = 11,
3558 HttpRuntimeClose = 12,
3560 InitializationError = 13,
3562 MaxRecompilationsReached = 14,
3564 BuildManagerChange = 15,