03161561576a4c58a3568c32128a6b6d69f48b8c
[mono.git] / mcs / class / referencesource / System.Web / HttpRuntime.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HttpRuntime.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 /*
8  * The ASP.NET runtime services
9  *
10  * Copyright (c) 1998 Microsoft Corporation
11  */
12
13 namespace System.Web {
14     using System;
15     using System.Collections;
16     using System.Configuration;
17     using System.Data;
18     using System.Data.Common;
19     using System.Diagnostics.CodeAnalysis;
20     using System.Globalization;
21     using System.IO;
22     using System.Net;
23     using System.Reflection;
24     using System.Resources;
25     using System.Runtime;
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;
33     using System.Text;
34     using System.Threading;
35     using System.Web;
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;
42     using System.Web.UI;
43     using System.Web.Util;
44     using System.Xml;
45     using Microsoft.Win32;
46
47     /// <devdoc>
48     ///    <para>Provides a set of ASP.NET runtime services.</para>
49     /// </devdoc>
50     public sealed class HttpRuntime {
51
52         internal const string codegenDirName = "Temporary ASP.NET Files";
53         internal const string profileFileName = "profileoptimization.prof";
54
55         private static HttpRuntime _theRuntime;   // single instance of the class
56         internal static byte[] s_autogenKeys = new byte[1024];
57
58         //
59         // Names of special ASP.NET directories
60         //
61
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";
71
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 = { '/', '?', '*', '<', '>', '|', '"' };
75
76
77
78 #if OLD
79         // For s_forbiddenDirs and s_forbiddenDirsConstant, see
80         // ndll.h, and RestrictIISFolders in regiis.cxx
81
82         internal static string[]    s_forbiddenDirs =   {
83                                         BinDirectoryName,
84                                         CodeDirectoryName,
85                                         DataDirectoryName,
86                                         ResourcesDirectoryName,
87                                         WebRefDirectoryName,
88                                     };
89
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,
96                                     };
97 #endif
98
99         static HttpRuntime() {
100             AddAppDomainTraceMessage("*HttpRuntime::cctor");
101
102             StaticInit();
103
104             _theRuntime = new HttpRuntime();
105
106             _theRuntime.Init();
107
108             AddAppDomainTraceMessage("HttpRuntime::cctor*");
109         }
110
111         [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
112         public HttpRuntime() {
113         }
114
115         //
116         // static initialization to get hooked up to the unmanaged code
117         // get installation directory, etc.
118         //
119
120         private static bool s_initialized = false;
121         private static String s_installDirectory;
122         private static bool s_isEngineLoaded = false;
123
124         // Force the static initialization of this class.
125         internal static void ForceStaticInit() { }
126
127         private static void StaticInit() {
128             if (s_initialized) {
129                 // already initialized
130                 return;
131             }
132
133             bool isEngineLoaded = false;
134             bool wasEngineLoadedHere = false;
135             String installDir = null;
136
137             // load webengine.dll if it is not loaded already
138
139 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
140
141             installDir = RuntimeEnvironment.GetRuntimeDirectory();
142
143             if (UnsafeNativeMethods.GetModuleHandle(ModName.ENGINE_FULL_NAME) != IntPtr.Zero) {
144                 isEngineLoaded = true;
145             }
146
147             // Load webengine.dll if not loaded already
148
149             if (!isEngineLoaded) {
150                 String fullPath = installDir + Path.DirectorySeparatorChar + ModName.ENGINE_FULL_NAME;
151
152                 if (UnsafeNativeMethods.LoadLibrary(fullPath) != IntPtr.Zero) {
153                     isEngineLoaded = true;
154                     wasEngineLoadedHere = true;
155                 }
156             }
157
158             if (isEngineLoaded) {
159                 UnsafeNativeMethods.InitializeLibrary(false);
160
161                 if (wasEngineLoadedHere) {
162                     UnsafeNativeMethods.PerfCounterInitialize();
163                 }
164             }
165
166 #else // !FEATURE_PAL
167             string p = typeof(object).Module.FullyQualifiedName;
168             installDir = Path.GetDirectoryName(p);
169 #endif // !FEATURE_PAL
170
171             s_installDirectory = installDir;
172             s_isEngineLoaded = isEngineLoaded;
173             s_initialized = true;
174
175             PopulateIISVersionInformation();
176
177             AddAppDomainTraceMessage("Initialize");
178         }
179
180         //
181         // Runtime services
182         //
183
184         private NamedPermissionSet _namedPermissionSet;
185         private PolicyLevel _policyLevel;
186         private string _hostSecurityPolicyResolverType = null;
187         private FileChangesMonitor _fcm;
188         private CacheInternal _cacheInternal;
189         private Cache _cachePublic;
190         private bool _isOnUNCShare;
191         private Profiler _profiler;
192         private RequestTimeoutManager _timeoutManager;
193         private RequestQueue _requestQueue;
194         private bool _apartmentThreading;
195
196         private bool _processRequestInApplicationTrust;
197         private bool _disableProcessRequestInApplicationTrust;
198         private bool _isLegacyCas;
199         //
200         // Counters
201         //
202
203         private bool _beforeFirstRequest = true;
204         private DateTime _firstRequestStartTime;
205         private bool _firstRequestCompleted;
206         private bool _userForcedShutdown;
207         private bool _configInited;
208         private bool _fusionInited;
209         private int _activeRequestCount;
210         private volatile bool _disposingHttpRuntime;
211         private DateTime _lastShutdownAttemptTime;
212         private bool _shutdownInProgress;
213         private String _shutDownStack;
214         private String _shutDownMessage;
215         private ApplicationShutdownReason _shutdownReason = ApplicationShutdownReason.None;
216         private string _trustLevel;
217         private string _wpUserId;
218         private bool _shutdownWebEventRaised;
219
220         //
221         // Header Newlines
222         //
223         private bool _enableHeaderChecking;
224
225         //
226         // Callbacks
227         //
228
229         private AsyncCallback _requestNotificationCompletionCallback;
230         private AsyncCallback _handlerCompletionCallback;
231         private HttpWorkerRequest.EndOfSendNotification _asyncEndOfSendCallback;
232         private WaitCallback _appDomainUnloadallback;
233
234         //
235         // Initialization error (to be reported on subsequent requests)
236         //
237
238         private Exception _initializationError;
239         private bool _hostingInitFailed; // make such errors non-sticky
240         private Timer _appDomainShutdownTimer = null;
241
242
243         //
244         // App domain related
245         //
246
247         private String _tempDir;
248         private String _codegenDir;
249         private String _appDomainAppId;
250         private String _appDomainAppPath;
251         private VirtualPath _appDomainAppVPath;
252         private String _appDomainId;
253
254         //
255         // Debugging support
256         //
257
258         private bool _debuggingEnabled = false;
259
260         //
261         // App_Offline.htm support
262         //
263
264         private const string AppOfflineFileName = "App_Offline.htm";
265         private const long MaxAppOfflineFileLength = 1024 * 1024;
266         private byte[] _appOfflineMessage;
267
268         //
269         // Client script support
270         //
271
272         private const string AspNetClientFilesSubDirectory = "asp.netclientfiles";
273         private const string AspNetClientFilesParentVirtualPath = "/aspnet_client/system_web/";
274         private string _clientScriptVirtualPath;
275         private string _clientScriptPhysicalPath;
276
277         //
278         // IIS version and whether we're using the integrated pipeline
279         //
280         private static Version _iisVersion;
281         private static bool _useIntegratedPipeline;
282
283         //
284         // Prefetch
285         //
286         private static bool _enablePrefetchOptimization;
287
288         /////////////////////////////////////////////////////////////////////////
289         // 3 steps of initialization:
290         //     Init() is called from HttpRuntime cctor
291         //     HostingInit() is called by the Hosting Environment
292         //     FirstRequestInit() is called on first HTTP request
293         //
294
295         /*
296          * Context-less initialization (on app domain creation)
297          */
298         private void Init() {
299             try {
300 #if !FEATURE_PAL
301                 if (Environment.OSVersion.Platform != PlatformID.Win32NT)
302                     throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT));
303 #else // !FEATURE_PAL
304                 // ROTORTODO
305                 // Do nothing: FEATURE_PAL environment will always support ASP.NET hosting
306 #endif // !FEATURE_PAL
307
308                 _profiler = new Profiler();
309                 _timeoutManager = new RequestTimeoutManager();
310                 _wpUserId = GetCurrentUserName();
311
312                 _requestNotificationCompletionCallback = new AsyncCallback(this.OnRequestNotificationCompletion);
313                 _handlerCompletionCallback = new AsyncCallback(this.OnHandlerCompletion);
314                 _asyncEndOfSendCallback = new HttpWorkerRequest.EndOfSendNotification(this.EndOfSendCallback);
315                 _appDomainUnloadallback = new WaitCallback(this.ReleaseResourcesAndUnloadAppDomain);
316
317
318                 // appdomain values
319                 if (GetAppDomainString(".appDomain") != null) {
320
321                     Debug.Assert(HostingEnvironment.IsHosted);
322
323                     _appDomainAppId = GetAppDomainString(".appId");
324                     _appDomainAppPath = GetAppDomainString(".appPath");
325                     _appDomainAppVPath = VirtualPath.CreateNonRelativeTrailingSlash(GetAppDomainString(".appVPath"));
326                     _appDomainId = GetAppDomainString(".domainId");
327
328                     _isOnUNCShare = StringUtil.StringStartsWith(_appDomainAppPath, "\\\\");
329
330                     // init perf counters for this appdomain
331                     PerfCounters.Open(_appDomainAppId);
332                 }
333                 else {
334                     Debug.Assert(!HostingEnvironment.IsHosted);
335                 }
336
337                 // _appDomainAppPath should be set before file change notifications are initialized
338                 // DevDiv 248126: Check httpRuntime fcnMode first before we use the registry key
339                 _fcm = new FileChangesMonitor(HostingEnvironment.FcnMode);
340             }
341             catch (Exception e) {
342                 // remember static initalization error
343                 InitializationException = e;
344             }
345         }
346
347         private void SetUpDataDirectory() {
348
349             // Set the DataDirectory (see VSWhidbey 226834) with permission (DevDiv 29614)
350             string dataDirectory = Path.Combine(_appDomainAppPath, DataDirectoryName);
351             AppDomain.CurrentDomain.SetData("DataDirectory", dataDirectory,
352                     new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dataDirectory));
353         }
354
355         private void DisposeAppDomainShutdownTimer() {
356             Timer timer = _appDomainShutdownTimer;
357             if (timer != null && Interlocked.CompareExchange(ref _appDomainShutdownTimer, null, timer) == timer) {
358                 timer.Dispose();
359             }
360         }
361
362         private void AppDomainShutdownTimerCallback(Object state) {
363             try {
364                 DisposeAppDomainShutdownTimer();
365                 ShutdownAppDomain(ApplicationShutdownReason.InitializationError, "Initialization Error");
366             }
367             catch { } // ignore exceptions
368         }
369
370         /*
371          * Restart the AppDomain in 10 seconds
372          */
373         private void StartAppDomainShutdownTimer() {
374             if (_appDomainShutdownTimer == null && !_shutdownInProgress) {
375                 lock (this) {
376                     if (_appDomainShutdownTimer == null && !_shutdownInProgress) {
377                         _appDomainShutdownTimer = new Timer(
378                             new TimerCallback(this.AppDomainShutdownTimerCallback),
379                             null,
380                             10 * 1000,
381                             0);
382                     }
383                 }
384             }
385         }
386
387
388         /*
389          * Initialization from HostingEnvironment of HTTP independent features
390          */
391         private void HostingInit(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) {
392             using (new ApplicationImpersonationContext()) {
393                 try {
394                     // To ignore FCN during initialization
395                     _firstRequestStartTime = DateTime.UtcNow;
396
397                     SetUpDataDirectory();
398
399                     // Throw an exception about lack of access to app directory early on
400                     EnsureAccessToApplicationDirectory();
401
402                     // Monitor renames to directories we are watching, and notifications on the bin directory
403                     //
404                     // Note that this must be the first monitoring that we do of the application directory.
405                     // There is a 
406
407
408
409
410                     StartMonitoringDirectoryRenamesAndBinDirectory();
411
412                     // Initialize ObjectCacheHost before config is read, since config relies on the cache
413                     if (InitializationException == null) {
414                         HostingEnvironment.InitializeObjectCacheHost();
415                     }
416
417                     //
418                     // Get the configuration needed to minimally initialize
419                     // the components required for a complete configuration system,
420                     // especially SetTrustLevel.
421                     //
422                     // We want to do this before calling SetUpCodegenDirectory(),
423                     // to remove the risk of the config system loading
424                     // codegen assemblies in full trust (VSWhidbey 460506)
425                     //
426                     CacheSection cacheSection;
427                     TrustSection trustSection;
428                     SecurityPolicySection securityPolicySection;
429                     CompilationSection compilationSection;
430                     HostingEnvironmentSection hostingEnvironmentSection;
431                     Exception configInitException;
432
433                     GetInitConfigSections(
434                             out cacheSection,
435                             out trustSection,
436                             out securityPolicySection,
437                             out compilationSection,
438                             out hostingEnvironmentSection,
439                             out configInitException);
440
441                     // Once the configuration system is initialized, we can read
442                     // the cache configuration settings.
443                     //
444                     // Note that we must do this after we start monitoring directory renames,
445                     // as reading config will cause file monitoring on the application directory
446                     // to occur.
447                     HttpRuntime.CacheInternal.ReadCacheInternalConfig(cacheSection);
448
449                     // Set up the codegen directory for the app.  This needs to be done before we process
450                     // the policy file, because it needs to replace the $CodeGen$ token.
451                     SetUpCodegenDirectory(compilationSection);
452
453                     if(compilationSection != null) {
454                         _enablePrefetchOptimization = compilationSection.EnablePrefetchOptimization;
455                         if(_enablePrefetchOptimization) {
456                             UnsafeNativeMethods.StartPrefetchActivity((uint)StringUtil.GetStringHashCode(_appDomainAppId));
457                         }
458                     }
459
460                     // NOTE: after calling SetUpCodegenDirectory(), and until we call SetTrustLevel(), we are at
461                     // risk of codegen assemblies being loaded in full trust.  No code that might cause
462                     // assembly loading should be added here! This is only valid if the legacyCasModel is set
463                     // to true in <trust> section.
464
465                     // Throw the original configuration exception from ApplicationManager if configuration is broken.
466                     if (appDomainCreationException != null) {
467                         throw appDomainCreationException;
468                     }
469
470                     if (trustSection == null || String.IsNullOrEmpty(trustSection.Level)) {
471                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "trust"));
472                     }
473
474                     if (trustSection.LegacyCasModel) {
475                         try {
476                             _disableProcessRequestInApplicationTrust = false;
477                             _isLegacyCas = true;
478                             // Set code access policy on the app domain
479                             SetTrustLevel(trustSection, securityPolicySection);
480                         }
481                         catch {
482                             // throw the original config exception if it exists
483                             if (configInitException != null)
484                                 throw configInitException;
485                             throw;
486                         }
487                     }
488                     else if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
489                         _trustLevel = "Full";
490                     }
491                     else {
492                         _disableProcessRequestInApplicationTrust = true;
493                         // Set code access policy properties of the runtime object
494                         SetTrustParameters(trustSection, securityPolicySection, policyLevel);
495                     }
496
497                     // Configure fusion to use directories set in the app config
498                     InitFusion(hostingEnvironmentSection);
499
500                     // set the sliding expiration for URL metadata
501                     CachedPathData.InitializeUrlMetadataSlidingExpiration(hostingEnvironmentSection);
502
503                     // Complete initialization of configuration.
504                     // Note that this needs to be called after SetTrustLevel,
505                     // as it indicates that we have the permission set needed
506                     // to correctly run configuration section handlers.
507                     // As little config should be read before CompleteInit() as possible.
508                     // No section that runs before CompleteInit() should demand permissions,
509                     // as the permissions set has not yet determined until SetTrustLevel()
510                     // is called.
511                     HttpConfigurationSystem.CompleteInit();
512
513                     //
514                     // If an exception occurred loading configuration,
515                     // we are now ready to handle exception processing
516                     // with the correct trust level set.
517                     //
518                     if (configInitException != null) {
519                         throw configInitException;
520                     }
521
522                     SetThreadPoolLimits();
523
524                     SetAutogenKeys();
525
526                     // Initialize the build manager
527                     BuildManager.InitializeBuildManager();
528
529                     if(compilationSection != null && compilationSection.ProfileGuidedOptimizations == ProfileGuidedOptimizationsFlags.All) {
530                         ProfileOptimization.SetProfileRoot(_codegenDir);
531                         ProfileOptimization.StartProfile(profileFileName);
532                     }
533
534                     // Determine apartment threading setting
535                     InitApartmentThreading();
536
537                     // Init debugging
538                     InitDebuggingSupport();
539
540                     _processRequestInApplicationTrust = trustSection.ProcessRequestInApplicationTrust;
541
542                     // Init AppDomain Resource Perf Counters
543                     AppDomainResourcePerfCounters.Init();
544
545
546                     RelaxMapPathIfRequired();
547                 }
548                 catch (Exception e) {
549                     _hostingInitFailed = true;
550                     InitializationException = e;
551
552                     Debug.Trace("AppDomainFactory", "HostingInit failed. " + e.ToString());
553
554                     if ((hostingFlags & HostingEnvironmentFlags.ThrowHostingInitErrors) != 0)
555                         throw;
556                 }
557             }
558         }
559
560         internal static Exception InitializationException {
561             get {
562                 return _theRuntime._initializationError;
563             }
564
565             // The exception is "cached" for 10 seconds, then the AppDomain is restarted.
566             set {
567                 _theRuntime._initializationError = value;
568                 // In v2.0, we shutdown immediately if hostingInitFailed...so we don't need the timer
569                 if (!HostingInitFailed) {
570                     _theRuntime.StartAppDomainShutdownTimer();
571                 }
572             }
573         }
574
575         internal static bool HostingInitFailed {
576             get {
577                 return _theRuntime._hostingInitFailed;
578             }
579         }
580
581         internal static void InitializeHostingFeatures(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) {
582             _theRuntime.HostingInit(hostingFlags, policyLevel, appDomainCreationException);
583         }
584
585         internal static bool EnableHeaderChecking {
586             get {
587                 return _theRuntime._enableHeaderChecking;
588             }
589         }
590
591         internal static bool ProcessRequestInApplicationTrust {
592             get {
593                 return _theRuntime._processRequestInApplicationTrust;
594             }
595         }
596
597         internal static bool DisableProcessRequestInApplicationTrust {
598             get {
599                 return _theRuntime._disableProcessRequestInApplicationTrust;
600             }
601         }
602
603         internal static bool IsLegacyCas {
604             get {
605                 return _theRuntime._isLegacyCas;
606             }
607         }
608
609         internal static byte[] AppOfflineMessage {
610             get {
611                 return _theRuntime._appOfflineMessage;
612             }
613         }
614
615         /*
616          * Initialization on first request (context available)
617          */
618         private void FirstRequestInit(HttpContext context) {
619             Exception error = null;
620
621             if (InitializationException == null && _appDomainId != null) {
622 #if DBG
623                 HttpContext.SetDebugAssertOnAccessToCurrent(true);
624 #endif
625                 try {
626                     using (new ApplicationImpersonationContext()) {
627                         // Is this necessary?  See InitHttpConfiguration
628                         CultureInfo savedCulture = Thread.CurrentThread.CurrentCulture;
629                         CultureInfo savedUICulture = Thread.CurrentThread.CurrentUICulture;
630
631                         try {
632                             // Ensure config system is initialized
633                             InitHttpConfiguration(); // be sure config system is set
634
635                             // Check if applicaton is enabled
636                             CheckApplicationEnabled();
637
638                             // Check access to temp compilation directory (under hosting identity)
639                             CheckAccessToTempDirectory();
640
641                             // Initialize health monitoring
642                             InitializeHealthMonitoring();
643
644                             // Init request queue (after reading config)
645                             InitRequestQueue();
646
647                             // configure the profiler according to config
648                             InitTrace(context);
649
650                             // Start heatbeat for Web Event Health Monitoring
651                             HealthMonitoringManager.StartHealthMonitoringHeartbeat();
652
653                             // Remove read and browse access of the bin directory
654                             RestrictIISFolders(context);
655
656                             // Preload all assemblies from bin (only if required).  ASURT 114486
657                             PreloadAssembliesFromBin();
658
659                             // Decide whether or not to encode headers.  VsWhidbey 257154
660                             InitHeaderEncoding();
661
662                             // Force the current encoder + validator to load so that there's a deterministic
663                             // place (here) for an exception to occur if there's a load error
664                             HttpEncoder.InitializeOnFirstRequest();
665                             RequestValidator.InitializeOnFirstRequest();
666
667                             if (context.WorkerRequest is ISAPIWorkerRequestOutOfProc) {
668                                 // Make sure that the <processModel> section has no errors
669                                 ProcessModelSection processModel = RuntimeConfig.GetMachineConfig().ProcessModel;
670                             }
671                         }
672                         finally {
673                             Thread.CurrentThread.CurrentUICulture = savedUICulture;
674                             SetCurrentThreadCultureWithAssert(savedCulture);
675                         }
676                     }
677                 }
678                 catch (ConfigurationException e) {
679                     error = e;
680                 }
681                 catch (Exception e) {
682                     // remember second-phase initialization error
683                     error = new HttpException(SR.GetString(SR.XSP_init_error, e.Message), e);
684                 }
685                 finally {
686 #if DBG
687                     HttpContext.SetDebugAssertOnAccessToCurrent(false);
688 #endif
689                 }
690             }
691
692             if (InitializationException != null) {
693                 // throw cached exception.  We need to wrap it in a new exception, otherwise
694                 // we lose the original stack.
695                 throw new HttpException(InitializationException.Message, InitializationException);
696             }
697             else if (error != null) {
698                 InitializationException = error;
699                 // throw new exception
700                 throw error;
701             }
702
703             AddAppDomainTraceMessage("FirstRequestInit");
704         }
705
706         [SecurityPermission(SecurityAction.Assert, ControlThread = true)]
707         internal static void SetCurrentThreadCultureWithAssert(CultureInfo cultureInfo) {
708             Thread.CurrentThread.CurrentCulture = cultureInfo;
709         }
710
711         private void EnsureFirstRequestInit(HttpContext context) {
712             if (_beforeFirstRequest) {
713                 lock (this) {
714                     if (_beforeFirstRequest) {
715                         _firstRequestStartTime = DateTime.UtcNow;
716                         FirstRequestInit(context);
717                         _beforeFirstRequest = false;
718                         context.FirstRequest = true;
719                     }
720                 }
721             }
722         }
723
724         private void EnsureAccessToApplicationDirectory() {
725             if (!FileUtil.DirectoryAccessible(_appDomainAppPath)) {
726                 // 
727                 if (_appDomainAppPath.IndexOf('?') >= 0) {
728                     // Possible Unicode when not supported
729                     throw new HttpException(SR.GetString(SR.Access_denied_to_unicode_app_dir, _appDomainAppPath));
730                 }
731                 else {
732                     throw new HttpException(SR.GetString(SR.Access_denied_to_app_dir, _appDomainAppPath));
733                 }
734             }
735         }
736
737         private void StartMonitoringDirectoryRenamesAndBinDirectory() {
738             _fcm.StartMonitoringDirectoryRenamesAndBinDirectory(AppDomainAppPathInternal, new FileChangeEventHandler(this.OnCriticalDirectoryChange));
739         }
740
741         //
742         // Monitor a local resources subdirectory and unload appdomain when it changes
743         //
744         internal static void StartListeningToLocalResourcesDirectory(VirtualPath virtualDir) {
745 #if !FEATURE_PAL // FEATURE_PAL does not enable file change notification
746             _theRuntime._fcm.StartListeningToLocalResourcesDirectory(virtualDir);
747 #endif // !FEATURE_PAL
748         }
749
750         //
751         // Get the configuration needed to minimally initialize
752         // the components required for a complete configuration system,
753         //
754         // Note that if the application configuration file has an error,
755         // AppLKGConfig will still retreive any valid configuration from
756         // that file, or from location directives that apply to the
757         // application path. This implies that an administrator can
758         // lock down an application's trust level in root web.config,
759         // and it will still take effect if the application's web.config
760         // has errors.
761         //
762         private void GetInitConfigSections(
763                 out CacheSection cacheSection,
764                 out TrustSection trustSection,
765                 out SecurityPolicySection securityPolicySection,
766                 out CompilationSection compilationSection,
767                 out HostingEnvironmentSection hostingEnvironmentSection,
768                 out Exception initException) {
769
770             cacheSection = null;
771             trustSection = null;
772             securityPolicySection = null;
773             compilationSection = null;
774             hostingEnvironmentSection = null;
775             initException = null;
776
777             // AppLKGConfig is guaranteed to not throw an exception.
778             RuntimeConfig appLKGConfig = RuntimeConfig.GetAppLKGConfig();
779
780             // AppConfig may throw an exception.
781             RuntimeConfig appConfig = null;
782             try {
783                 appConfig = RuntimeConfig.GetAppConfig();
784             }
785             catch (Exception e) {
786                 initException = e;
787             }
788
789             // Cache section
790             if (appConfig != null) {
791                 try {
792                     cacheSection = appConfig.Cache;
793                 }
794                 catch (Exception e) {
795                     if (initException == null) {
796                         initException = e;
797                     }
798                 }
799             }
800
801             if (cacheSection == null) {
802                 cacheSection = appLKGConfig.Cache;
803             }
804
805             // Trust section
806             if (appConfig != null) {
807                 try {
808                     trustSection = appConfig.Trust;
809                 }
810                 catch (Exception e) {
811                     if (initException == null) {
812                         initException = e;
813                     }
814                 }
815             }
816
817             if (trustSection == null) {
818                 trustSection = appLKGConfig.Trust;
819             }
820
821             // SecurityPolicy section
822             if (appConfig != null) {
823                 try {
824                     securityPolicySection = appConfig.SecurityPolicy;
825                 }
826                 catch (Exception e) {
827                     if (initException == null) {
828                         initException = e;
829                     }
830                 }
831             }
832
833             if (securityPolicySection == null) {
834                 securityPolicySection = appLKGConfig.SecurityPolicy;
835             }
836
837             // Compilation section
838             if (appConfig != null) {
839                 try {
840                     compilationSection = appConfig.Compilation;
841                 }
842                 catch (Exception e) {
843                     if (initException == null) {
844                         initException = e;
845                     }
846                 }
847             }
848
849             if (compilationSection == null) {
850                 compilationSection = appLKGConfig.Compilation;
851             }
852
853             // HostingEnvironment section
854             if (appConfig != null) {
855                 try {
856                     hostingEnvironmentSection = appConfig.HostingEnvironment;
857                 }
858                 catch (Exception e) {
859                     if (initException == null) {
860                         initException = e;
861                     }
862                 }
863             }
864
865             if (hostingEnvironmentSection == null) {
866                 hostingEnvironmentSection = appLKGConfig.HostingEnvironment;
867             }
868         }
869
870         // Set up the codegen directory for the app
871         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This call site is trusted.")]
872         private void SetUpCodegenDirectory(CompilationSection compilationSection) {
873             AppDomain appDomain = Thread.GetDomain();
874
875             string codegenBase;
876             
877             // devdiv 1038337. Passing the corresponding IsDevelopmentEnvironment flag to ConstructSimpleAppName
878             string simpleAppName = System.Web.Hosting.AppManagerAppDomainFactory.ConstructSimpleAppName(
879                 AppDomainAppVirtualPath, HostingEnvironment.IsDevelopmentEnvironment);
880
881             string tempDirectory = null;
882
883             // These variables are used for error handling
884             string tempDirAttribName = null;
885             string configFileName = null;
886             int configLineNumber = 0;
887
888             if (compilationSection != null && !String.IsNullOrEmpty(compilationSection.TempDirectory)) {
889                 tempDirectory = compilationSection.TempDirectory;
890
891                 compilationSection.GetTempDirectoryErrorInfo(out tempDirAttribName,
892                     out configFileName, out configLineNumber);
893             }
894
895             if (tempDirectory != null) {
896                 tempDirectory = tempDirectory.Trim();
897
898                 if (!Path.IsPathRooted(tempDirectory)) {
899                     // Make sure the path is not relative (VSWhidbey 260075)
900                     tempDirectory = null;
901                 }
902                 else {
903                     try {
904                         // Canonicalize it to avoid problems with spaces (VSWhidbey 229873)
905                         tempDirectory = new DirectoryInfo(tempDirectory).FullName;
906                     }
907                     catch {
908                         tempDirectory = null;
909                     }
910                 }
911
912                 if (tempDirectory == null) {
913                     throw new ConfigurationErrorsException(
914                         SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
915                         configFileName, configLineNumber);
916                 }
917 #if FEATURE_PAL
918             } else {
919                 System.UInt32 length = 0;
920                 StringBuilder sb = null;
921                 bool bRet;
922
923                 // Get the required length
924                 bRet = UnsafeNativeMethods.GetUserTempDirectory(
925                                     UnsafeNativeMethods.DeploymentDirectoryType.ddtInstallationDependentDirectory,
926                                     null, ref length);
927
928                 if (true == bRet) {
929                     // now, allocate the string
930                     sb = new StringBuilder ((int)length);
931
932                     // call again to get the value
933                     bRet = UnsafeNativeMethods.GetUserTempDirectory(
934                                     UnsafeNativeMethods.DeploymentDirectoryType.ddtInstallationDependentDirectory,
935                                     sb, ref length);
936                 }
937
938                 if (false == bRet) {
939                     throw new ConfigurationException(
940                         HttpRuntime.FormatResourceString(SR.Invalid_temp_directory, tempDirAttribName));
941                 }
942
943                 tempDirectory = Path.Combine(sb.ToString(), codegenDirName);
944             }
945
946             // Always try to create the ASP.Net temp directory for FEATURE_PAL
947 #endif // FEATURE_PAL
948
949                 // Create the config-specified directory if needed
950                 try {
951                     Directory.CreateDirectory(tempDirectory);
952                 }
953                 catch (Exception e) {
954                     throw new ConfigurationErrorsException(
955                         SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
956                         e,
957                         configFileName, configLineNumber);
958                 }
959 #if !FEATURE_PAL
960             }
961             else {
962                 tempDirectory = Path.Combine(s_installDirectory, codegenDirName);
963             }
964 #endif // !FEATURE_PAL
965
966             // If we don't have write access to the codegen dir, use the TEMP dir instead.
967             // This will allow non-admin users to work in hosting scenarios (e.g. Venus, aspnet_compiler)
968             if (!System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory)) {
969
970                 // Don't do this if we are not in a CBM scenario and we're in a service (!UserInteractive), 
971                 // as TEMP could point to unwanted places.
972
973 #if !FEATURE_PAL // always fail here
974                 if ((!BuildManagerHost.InClientBuildManager) && (!Environment.UserInteractive))
975 #endif // !FEATURE_PAL
976                 {
977                     throw new HttpException(SR.GetString(SR.No_codegen_access,
978                         System.Web.UI.Util.GetCurrentAccountName(), tempDirectory));
979                 }
980
981                 tempDirectory = Path.GetTempPath();
982                 Debug.Assert(System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory));
983                 tempDirectory = Path.Combine(tempDirectory, codegenDirName);
984             }
985
986             _tempDir = tempDirectory;
987
988             codegenBase = Path.Combine(tempDirectory, simpleAppName);
989
990 #pragma warning disable 0618    // To avoid deprecation warning
991             appDomain.SetDynamicBase(codegenBase);
992 #pragma warning restore 0618
993
994             _codegenDir = Thread.GetDomain().DynamicDirectory;
995
996             // Create the codegen directory if needed
997             Directory.CreateDirectory(_codegenDir);
998         }
999
1000         private void InitFusion(HostingEnvironmentSection hostingEnvironmentSection) {
1001
1002             AppDomain appDomain = Thread.GetDomain();
1003
1004             // If there is a double backslash in the string, get rid of it (ASURT 122191)
1005             // Make sure to skip the first char, to avoid breaking the UNC case
1006             string appDomainAppPath = _appDomainAppPath;
1007             if (appDomainAppPath.IndexOf(DoubleDirectorySeparatorString, 1, StringComparison.Ordinal) >= 1) {
1008                 appDomainAppPath = appDomainAppPath[0] + appDomainAppPath.Substring(1).Replace(DoubleDirectorySeparatorString,
1009                     DirectorySeparatorString);
1010             }
1011
1012 #pragma warning disable 0618    // To avoid deprecation warning
1013             // Allow assemblies from 'bin' to be loaded
1014             appDomain.AppendPrivatePath(appDomainAppPath + BinDirectoryName);
1015 #pragma warning restore 0618
1016
1017             // If shadow copying was disabled via config, turn it off (DevDiv 30864)
1018             if (hostingEnvironmentSection != null && !hostingEnvironmentSection.ShadowCopyBinAssemblies) {
1019 #pragma warning disable 0618    // To avoid deprecation warning
1020                 appDomain.ClearShadowCopyPath();
1021 #pragma warning restore 0618
1022             }
1023             else {
1024                 // enable shadow-copying from bin
1025 #pragma warning disable 0618    // To avoid deprecation warning
1026                 appDomain.SetShadowCopyPath(appDomainAppPath + BinDirectoryName);
1027 #pragma warning restore 0618
1028             }
1029
1030             // Get rid of the last part of the directory (the app name), since it will
1031             // be re-appended.
1032             string parentDir = Directory.GetParent(_codegenDir).FullName;
1033 #pragma warning disable 0618    // To avoid deprecation warning
1034             appDomain.SetCachePath(parentDir);
1035 #pragma warning restore 0618
1036
1037             _fusionInited = true;
1038         }
1039
1040         private void InitRequestQueue() {
1041             RuntimeConfig config = RuntimeConfig.GetAppConfig();
1042             HttpRuntimeSection runtimeConfig = config.HttpRuntime;
1043             ProcessModelSection processConfig = config.ProcessModel;
1044
1045             if (processConfig.AutoConfig) {
1046                 _requestQueue = new RequestQueue(
1047                     88 * processConfig.CpuCount,
1048                     76 * processConfig.CpuCount,
1049                     runtimeConfig.AppRequestQueueLimit,
1050                     processConfig.ClientConnectedCheck);
1051             }
1052             else {
1053
1054                 // Configuration section handlers cannot validate values based on values
1055                 // in other configuration sections, so we validate minFreeThreads and
1056                 // minLocalRequestFreeThreads here.
1057                 int maxThreads = (processConfig.MaxWorkerThreadsTimesCpuCount < processConfig.MaxIoThreadsTimesCpuCount) ? processConfig.MaxWorkerThreadsTimesCpuCount : processConfig.MaxIoThreadsTimesCpuCount;
1058                 // validate minFreeThreads
1059                 if (runtimeConfig.MinFreeThreads >= maxThreads) {
1060                     if (runtimeConfig.ElementInformation.Properties["minFreeThreads"].LineNumber == 0) {
1061                         if (processConfig.ElementInformation.Properties["maxWorkerThreads"].LineNumber != 0) {
1062                             throw new ConfigurationErrorsException(SR.GetString(SR.Thread_pool_limit_must_be_greater_than_minFreeThreads, runtimeConfig.MinFreeThreads.ToString(CultureInfo.InvariantCulture)),
1063                                                                    processConfig.ElementInformation.Properties["maxWorkerThreads"].Source,
1064                                                                    processConfig.ElementInformation.Properties["maxWorkerThreads"].LineNumber);
1065                         }
1066                         else {
1067                             throw new ConfigurationErrorsException(SR.GetString(SR.Thread_pool_limit_must_be_greater_than_minFreeThreads, runtimeConfig.MinFreeThreads.ToString(CultureInfo.InvariantCulture)),
1068                                                                    processConfig.ElementInformation.Properties["maxIoThreads"].Source,
1069                                                                    processConfig.ElementInformation.Properties["maxIoThreads"].LineNumber);
1070                         }
1071                     }
1072                     else {
1073                         throw new ConfigurationErrorsException(SR.GetString(SR.Min_free_threads_must_be_under_thread_pool_limits, maxThreads.ToString(CultureInfo.InvariantCulture)),
1074                                                                runtimeConfig.ElementInformation.Properties["minFreeThreads"].Source,
1075                                                                runtimeConfig.ElementInformation.Properties["minFreeThreads"].LineNumber);
1076                     }
1077                 }
1078                 // validate minLocalRequestFreeThreads
1079                 if (runtimeConfig.MinLocalRequestFreeThreads > runtimeConfig.MinFreeThreads) {
1080                     if (runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].LineNumber == 0) {
1081                         throw new ConfigurationErrorsException(SR.GetString(SR.Local_free_threads_cannot_exceed_free_threads),
1082                                                                processConfig.ElementInformation.Properties["minFreeThreads"].Source,
1083                                                                processConfig.ElementInformation.Properties["minFreeThreads"].LineNumber);
1084                     }
1085                     else {
1086                         throw new ConfigurationErrorsException(SR.GetString(SR.Local_free_threads_cannot_exceed_free_threads),
1087                                                                runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].Source,
1088                                                                runtimeConfig.ElementInformation.Properties["minLocalRequestFreeThreads"].LineNumber);
1089                     }
1090                 }
1091
1092                 _requestQueue = new RequestQueue(
1093                     runtimeConfig.MinFreeThreads,
1094                     runtimeConfig.MinLocalRequestFreeThreads,
1095                     runtimeConfig.AppRequestQueueLimit,
1096                     processConfig.ClientConnectedCheck);
1097             }
1098         }
1099
1100         private void InitApartmentThreading() {
1101             HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1102
1103             if (runtimeConfig != null) {
1104                 _apartmentThreading = runtimeConfig.ApartmentThreading;
1105             }
1106             else {
1107                 _apartmentThreading = false;
1108             }
1109         }
1110
1111         private void InitTrace(HttpContext context) {
1112             TraceSection traceConfig = RuntimeConfig.GetAppConfig().Trace;
1113
1114             Profile.RequestsToProfile = traceConfig.RequestLimit;
1115             Profile.PageOutput = traceConfig.PageOutput;
1116             Profile.OutputMode = TraceMode.SortByTime;
1117             if (traceConfig.TraceMode == TraceDisplayMode.SortByCategory)
1118                 Profile.OutputMode = TraceMode.SortByCategory;
1119
1120             Profile.LocalOnly = traceConfig.LocalOnly;
1121             Profile.IsEnabled = traceConfig.Enabled;
1122             Profile.MostRecent = traceConfig.MostRecent;
1123             Profile.Reset();
1124
1125             // the first request's context is created before InitTrace, so
1126             // we need to set this manually. (ASURT 93730)
1127             context.TraceIsEnabled = traceConfig.Enabled;
1128             TraceContext.SetWriteToDiagnosticsTrace(traceConfig.WriteToDiagnosticsTrace);
1129         }
1130
1131         private void InitDebuggingSupport() {
1132             CompilationSection compConfig = RuntimeConfig.GetAppConfig().Compilation;
1133             _debuggingEnabled = compConfig.Debug;
1134         }
1135
1136         /*
1137          * Pre-load all the bin assemblies if we're impersonated.  This way, if user code
1138          * calls Assembly.Load while impersonated, the assembly will already be loaded, and
1139          * we won't fail due to lack of permissions on the codegen dir (see ASURT 114486)
1140          */
1141         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1142         private void PreloadAssembliesFromBin() {
1143             bool appClientImpersonationEnabled = false;
1144
1145             if (!_isOnUNCShare) {
1146                 // if not on UNC share check if config has impersonation enabled (without userName)
1147                 IdentitySection c = RuntimeConfig.GetAppConfig().Identity;
1148                 if (c.Impersonate && c.ImpersonateToken == IntPtr.Zero)
1149                     appClientImpersonationEnabled = true;
1150             }
1151
1152             if (!appClientImpersonationEnabled)
1153                 return;
1154
1155             // Get the path to the bin directory
1156             string binPath = HttpRuntime.BinDirectoryInternal;
1157
1158             DirectoryInfo binPathDirectory = new DirectoryInfo(binPath);
1159
1160             if (!binPathDirectory.Exists)
1161                 return;
1162
1163             PreloadAssembliesFromBinRecursive(binPathDirectory);
1164         }
1165
1166         private void PreloadAssembliesFromBinRecursive(DirectoryInfo dirInfo) {
1167
1168             FileInfo[] binDlls = dirInfo.GetFiles("*.dll");
1169
1170             // Pre-load all the assemblies, ignoring all exceptions
1171             foreach (FileInfo fi in binDlls) {
1172                 try { Assembly.Load(System.Web.UI.Util.GetAssemblyNameFromFileName(fi.Name)); }
1173                 catch (FileNotFoundException) {
1174                     // If Load failed, try LoadFrom (VSWhidbey 493725)
1175                     try { Assembly.LoadFrom(fi.FullName); }
1176                     catch { }
1177                 }
1178                 catch { }
1179             }
1180
1181             // Recurse on the subdirectories
1182             DirectoryInfo[] subDirs = dirInfo.GetDirectories();
1183             foreach (DirectoryInfo di in subDirs) {
1184                 PreloadAssembliesFromBinRecursive(di);
1185             }
1186         }
1187
1188         private void SetAutoConfigLimits(ProcessModelSection pmConfig) {
1189             // check if the current limits are ok
1190             int workerMax, ioMax;
1191             ThreadPool.GetMaxThreads(out workerMax, out ioMax);
1192
1193             // only set if different
1194             if (pmConfig.DefaultMaxWorkerThreadsForAutoConfig != workerMax || pmConfig.DefaultMaxIoThreadsForAutoConfig != ioMax) {
1195                 Debug.Trace("ThreadPool", "SetThreadLimit: from " + workerMax + "," + ioMax + " to " + pmConfig.DefaultMaxWorkerThreadsForAutoConfig + "," + pmConfig.DefaultMaxIoThreadsForAutoConfig);
1196                 UnsafeNativeMethods.SetClrThreadPoolLimits(pmConfig.DefaultMaxWorkerThreadsForAutoConfig, pmConfig.DefaultMaxIoThreadsForAutoConfig, true);
1197             }
1198
1199             // this is the code equivalent of setting maxconnection
1200             // Dev11 141729: Make autoConfig scale by default
1201             // Dev11 144842: PERF: Consider removing Max connection limit or changing the default value
1202             System.Net.ServicePointManager.DefaultConnectionLimit = Int32.MaxValue;
1203
1204             // we call InitRequestQueue later, from FirstRequestInit, and set minFreeThreads and minLocalRequestFreeThreads
1205         }
1206
1207         private void SetThreadPoolLimits() {
1208             try {
1209                 ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
1210
1211                 if (pmConfig.AutoConfig) {
1212                     // use recommendation in http://support.microsoft.com/?id=821268
1213                     SetAutoConfigLimits(pmConfig);
1214                 }
1215                 else if (pmConfig.MaxWorkerThreadsTimesCpuCount > 0 && pmConfig.MaxIoThreadsTimesCpuCount > 0) {
1216                     // check if the current limits are ok
1217                     int workerMax, ioMax;
1218                     ThreadPool.GetMaxThreads(out workerMax, out ioMax);
1219
1220                     // only set if different
1221                     if (pmConfig.MaxWorkerThreadsTimesCpuCount != workerMax || pmConfig.MaxIoThreadsTimesCpuCount != ioMax) {
1222                         Debug.Trace("ThreadPool", "SetThreadLimit: from " + workerMax + "," + ioMax + " to " + pmConfig.MaxWorkerThreadsTimesCpuCount + "," + pmConfig.MaxIoThreadsTimesCpuCount);
1223                         UnsafeNativeMethods.SetClrThreadPoolLimits(pmConfig.MaxWorkerThreadsTimesCpuCount, pmConfig.MaxIoThreadsTimesCpuCount, false);
1224                     }
1225                 }
1226
1227                 if (pmConfig.MinWorkerThreadsTimesCpuCount > 0 || pmConfig.MinIoThreadsTimesCpuCount > 0) {
1228                     int currentMinWorkerThreads, currentMinIoThreads;
1229                     ThreadPool.GetMinThreads(out currentMinWorkerThreads, out currentMinIoThreads);
1230
1231                     int newMinWorkerThreads = pmConfig.MinWorkerThreadsTimesCpuCount > 0 ? pmConfig.MinWorkerThreadsTimesCpuCount : currentMinWorkerThreads;
1232                     int newMinIoThreads = pmConfig.MinIoThreadsTimesCpuCount > 0 ? pmConfig.MinIoThreadsTimesCpuCount : currentMinIoThreads;
1233
1234                     if (newMinWorkerThreads > 0 && newMinIoThreads > 0
1235                         && (newMinWorkerThreads != currentMinWorkerThreads || newMinIoThreads != currentMinIoThreads))
1236                         ThreadPool.SetMinThreads(newMinWorkerThreads, newMinIoThreads);
1237                 }
1238             }
1239             catch {
1240             }
1241         }
1242
1243         internal static void CheckApplicationEnabled() {
1244             // process App_Offline.htm file
1245             string appOfflineFile = Path.Combine(_theRuntime._appDomainAppPath, AppOfflineFileName);
1246             bool appOfflineFileFound = false;
1247
1248             // monitor even if doesn't exist
1249             _theRuntime._fcm.StartMonitoringFile(appOfflineFile, new FileChangeEventHandler(_theRuntime.OnAppOfflineFileChange));
1250
1251             // read the file into memory
1252             try {
1253                 if (File.Exists(appOfflineFile)) {
1254                     Debug.Trace("AppOffline", "File " + appOfflineFile + " exists. Using it.");
1255
1256                     using (FileStream fs = new FileStream(appOfflineFile, FileMode.Open, FileAccess.Read, FileShare.Read)) {
1257                         if (fs.Length <= MaxAppOfflineFileLength) {
1258                             int length = (int)fs.Length;
1259
1260                             if (length > 0) {
1261                                 byte[] message = new byte[length];
1262
1263                                 if (fs.Read(message, 0, length) == length) {
1264                                     // remember the message
1265                                     _theRuntime._appOfflineMessage = message;
1266                                     appOfflineFileFound = true;
1267                                 }
1268                             }
1269                             else {
1270                                 // empty file
1271                                 appOfflineFileFound = true;
1272                                 _theRuntime._appOfflineMessage = new byte[0];
1273                             }
1274                         }
1275                     }
1276                 }
1277             }
1278             catch {
1279                 // ignore any IO errors reading the file
1280             }
1281
1282             // throw if there is a valid App_Offline file
1283             if (appOfflineFileFound) {
1284                 throw new HttpException(503, String.Empty);
1285             }
1286
1287             // process the config setting
1288             HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1289             if (!runtimeConfig.Enable) {
1290                 // throw 404 on first request init -- this will get cached until config changes
1291                 throw new HttpException(404, String.Empty);
1292             }
1293         }
1294
1295         [FileIOPermission(SecurityAction.Assert, Unrestricted = true)]
1296         private void CheckAccessToTempDirectory() {
1297             // The original check (in HostingInit) was done under process identity
1298             // this time we do it under hosting identity
1299             if (HostingEnvironment.HasHostingIdentity) {
1300                 using (new ApplicationImpersonationContext()) {
1301                     if (!System.Web.UI.Util.HasWriteAccessToDirectory(_tempDir)) {
1302                         throw new HttpException(SR.GetString(SR.No_codegen_access,
1303                             System.Web.UI.Util.GetCurrentAccountName(), _tempDir));
1304                     }
1305                 }
1306             }
1307         }
1308
1309         private void InitializeHealthMonitoring() {
1310 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
1311             ProcessModelSection pmConfig = RuntimeConfig.GetMachineConfig().ProcessModel;
1312             int deadLockInterval = (int)pmConfig.ResponseDeadlockInterval.TotalSeconds;
1313             int requestQueueLimit = pmConfig.RequestQueueLimit;
1314             Debug.Trace("HealthMonitor", "Initalizing: ResponseDeadlockInterval=" + deadLockInterval);
1315             UnsafeNativeMethods.InitializeHealthMonitor(deadLockInterval, requestQueueLimit);
1316 #endif // !FEATURE_PAL
1317         }
1318
1319         private static void InitHttpConfiguration() {
1320             if (!_theRuntime._configInited) {
1321                 _theRuntime._configInited = true;
1322
1323                 HttpConfigurationSystem.EnsureInit(null, true, true);
1324
1325                 // whenever possible report errors in the user's culture (from machine.config)
1326                 // Note: this thread's culture is saved/restored during FirstRequestInit, so this is safe
1327                 // see ASURT 81655
1328
1329                 GlobalizationSection globConfig = RuntimeConfig.GetAppLKGConfig().Globalization;
1330                 if (globConfig != null) {
1331                     if (!String.IsNullOrEmpty(globConfig.Culture) &&
1332                         !StringUtil.StringStartsWithIgnoreCase(globConfig.Culture, "auto"))
1333                         SetCurrentThreadCultureWithAssert(HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.Culture));
1334
1335                     if (!String.IsNullOrEmpty(globConfig.UICulture) &&
1336                         !StringUtil.StringStartsWithIgnoreCase(globConfig.UICulture, "auto"))
1337                         Thread.CurrentThread.CurrentUICulture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
1338                 }
1339
1340                 // check for errors in <processModel> section
1341                 RuntimeConfig appConfig = RuntimeConfig.GetAppConfig();
1342                 object section = appConfig.ProcessModel;
1343                 // check for errors in <hostingEnvironment> section
1344                 section = appConfig.HostingEnvironment;
1345             }
1346         }
1347
1348         private void InitHeaderEncoding() {
1349             HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppConfig().HttpRuntime;
1350             _enableHeaderChecking = runtimeConfig.EnableHeaderChecking;
1351         }
1352
1353         private static void SetAutogenKeys() {
1354 #if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
1355             byte[] bKeysRandom = new byte[s_autogenKeys.Length];
1356             byte[] bKeysStored = new byte[s_autogenKeys.Length];
1357             bool fGetStoredKeys = false;
1358             RNGCryptoServiceProvider randgen = new RNGCryptoServiceProvider();
1359
1360             // Gernerate random keys
1361             randgen.GetBytes(bKeysRandom);
1362
1363             // If getting stored keys via WorkerRequest object failed, get it directly
1364             if (!fGetStoredKeys)
1365                 fGetStoredKeys = (UnsafeNativeMethods.EcbCallISAPI(IntPtr.Zero, UnsafeNativeMethods.CallISAPIFunc.GetAutogenKeys,
1366                                                                    bKeysRandom, bKeysRandom.Length, bKeysStored, bKeysStored.Length) == 1);
1367
1368             // If we managed to get stored keys, copy them in; else use random keys
1369             if (fGetStoredKeys)
1370                 Buffer.BlockCopy(bKeysStored, 0, s_autogenKeys, 0, s_autogenKeys.Length);
1371             else
1372                 Buffer.BlockCopy(bKeysRandom, 0, s_autogenKeys, 0, s_autogenKeys.Length);
1373 #endif // !FEATURE_PAL
1374         }
1375
1376         internal static void IncrementActivePipelineCount() {
1377             Interlocked.Increment(ref _theRuntime._activeRequestCount);
1378             HostingEnvironment.IncrementBusyCount();
1379         }
1380
1381         internal static void DecrementActivePipelineCount() {
1382             HostingEnvironment.DecrementBusyCount();
1383             Interlocked.Decrement(ref _theRuntime._activeRequestCount);
1384         }
1385
1386         internal static void PopulateIISVersionInformation() {
1387             if (IsEngineLoaded) {
1388                 uint dwVersion;
1389                 bool fIsIntegratedMode;
1390                 UnsafeIISMethods.MgdGetIISVersionInformation(out dwVersion, out fIsIntegratedMode);
1391
1392                 if (dwVersion != 0) {
1393                     // High word is the major version; low word is the minor version (this is MAKELONG format)
1394                     _iisVersion = new Version((int)(dwVersion >> 16), (int)(dwVersion & 0xffff));
1395                     _useIntegratedPipeline = fIsIntegratedMode;
1396                 }
1397             }
1398         }
1399
1400         // Gets the version of IIS (7.0, 7.5, 8.0, etc.) that is hosting this application, or null if this application isn't IIS-hosted.
1401         // Should also return the correct version for IIS Express.
1402         public static Version IISVersion {
1403             get {
1404                 return _iisVersion;
1405             }
1406         }
1407
1408         // DevDivBugs 190952: public method for querying runtime pipeline mode
1409         public static bool UsingIntegratedPipeline {
1410             get {
1411                 return UseIntegratedPipeline;
1412             }
1413         }
1414
1415         internal static bool UseIntegratedPipeline {
1416             get {
1417                 return _useIntegratedPipeline;
1418             }
1419         }
1420
1421         internal static bool EnablePrefetchOptimization {
1422             get {
1423                 return _enablePrefetchOptimization;
1424             }
1425         }
1426
1427         /*
1428          * Process one step of the integrated pipeline
1429          *
1430          */
1431
1432         internal static RequestNotificationStatus ProcessRequestNotification(IIS7WorkerRequest wr, HttpContext context)
1433         {
1434             return _theRuntime.ProcessRequestNotificationPrivate(wr, context);
1435         }
1436
1437         private RequestNotificationStatus ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) {
1438             RequestNotificationStatus status = RequestNotificationStatus.Pending;
1439             try {
1440                 int currentModuleIndex;
1441                 bool isPostNotification;
1442                 int currentNotification;
1443
1444                 // setup the HttpContext for this event/module combo
1445                 UnsafeIISMethods.MgdGetCurrentNotificationInfo(wr.RequestContext, out currentModuleIndex, out isPostNotification, out currentNotification);
1446
1447                 context.CurrentModuleIndex = currentModuleIndex;
1448                 context.IsPostNotification = isPostNotification;
1449                 context.CurrentNotification = (RequestNotification) currentNotification;
1450 #if DBG
1451                 Debug.Trace("PipelineRuntime", "HttpRuntime::ProcessRequestNotificationPrivate: notification=" + context.CurrentNotification.ToString()
1452                             + ", isPost=" + context.IsPostNotification
1453                             + ", moduleIndex=" + context.CurrentModuleIndex);
1454 #endif
1455
1456                 IHttpHandler handler = null;
1457                 if (context.NeedToInitializeApp()) {
1458 #if DBG
1459                     Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
1460                                 "*** FirstNotification " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
1461                                 + ": _appDomainAppId=" + _appDomainAppId);
1462 #endif
1463                     // First request initialization
1464                     try {
1465                         EnsureFirstRequestInit(context);
1466                     }
1467                     catch {
1468                         // If we are handling a DEBUG request, ignore the FirstRequestInit exception.
1469                         // This allows the HttpDebugHandler to execute, and lets the debugger attach to
1470                         // the process (VSWhidbey 358135)
1471                         if (!context.Request.IsDebuggingRequest) {
1472                             throw;
1473                         }
1474                     }
1475
1476                     context.Response.InitResponseWriter();
1477                     handler = HttpApplicationFactory.GetApplicationInstance(context);
1478                     if (handler == null)
1479                         throw new HttpException(SR.GetString(SR.Unable_create_app_object));
1480
1481                     if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, handler.GetType().FullName, "Start");
1482
1483                     HttpApplication app = handler as HttpApplication;
1484                     if (app != null) {
1485                         // associate the context with an application instance
1486                         app.AssignContext(context);
1487                     }
1488                 }
1489
1490                 // this may throw, and should be called after app initialization
1491                 wr.SynchronizeVariables(context);
1492
1493                 if (context.ApplicationInstance != null) {
1494                     // process request
1495                     IAsyncResult ar = context.ApplicationInstance.BeginProcessRequestNotification(context, _requestNotificationCompletionCallback);
1496
1497                     if (ar.CompletedSynchronously) {
1498                         status = RequestNotificationStatus.Continue;
1499                     }
1500                 }
1501                 else if (handler != null) {
1502                     // HttpDebugHandler is processed here
1503                     handler.ProcessRequest(context);
1504                     status = RequestNotificationStatus.FinishRequest;
1505                 }
1506                 else {
1507                     status = RequestNotificationStatus.Continue;
1508                 }
1509             }
1510             catch (Exception e) {
1511                 status = RequestNotificationStatus.FinishRequest;
1512                 context.Response.InitResponseWriter();
1513                 // errors are handled in HttpRuntime::FinishRequestNotification
1514                 context.AddError(e);
1515             }
1516
1517             if (status != RequestNotificationStatus.Pending) {
1518                 // we completed synchronously
1519                 FinishRequestNotification(wr, context, ref status);
1520             }
1521
1522 #if DBG
1523             Debug.Trace("PipelineRuntime", "HttpRuntime::ProcessRequestNotificationPrivate: status=" + status.ToString());
1524 #endif
1525
1526             return status;
1527         }
1528
1529         private void FinishRequestNotification(IIS7WorkerRequest wr, HttpContext context, ref RequestNotificationStatus status) {
1530
1531             Debug.Assert(status != RequestNotificationStatus.Pending, "status != RequestNotificationStatus.Pending");
1532
1533             HttpApplication app = context.ApplicationInstance;
1534
1535             if (context.NotificationContext.RequestCompleted) {
1536                 status = RequestNotificationStatus.FinishRequest;
1537             }
1538
1539             // check if the app offline or whether an error has occurred, and report the condition
1540             context.ReportRuntimeErrorIfExists(ref status);
1541
1542             // we do not return FinishRequest for LogRequest or EndRequest
1543             if (status == RequestNotificationStatus.FinishRequest
1544                 && (context.CurrentNotification == RequestNotification.LogRequest
1545                     || context.CurrentNotification == RequestNotification.EndRequest)) {
1546                 status = RequestNotificationStatus.Continue;
1547             }
1548
1549             IntPtr requestContext = wr.RequestContext;
1550             bool sendHeaders = UnsafeIISMethods.MgdIsLastNotification(requestContext, status);
1551             try {
1552                 context.Response.UpdateNativeResponse(sendHeaders);
1553             }
1554             catch(Exception e) {
1555                 // if we catch an exception here then
1556                 // i) clear cached response body bytes on the worker request
1557                 // ii) clear the managed headers, the IIS native headers, the mangaged httpwriter response buffers, and the native IIS response buffers
1558                 // iii) attempt to format the exception and write it to the response
1559                 wr.UnlockCachedResponseBytes();
1560                 context.AddError(e);
1561                 context.ReportRuntimeErrorIfExists(ref status);
1562                 try {
1563                     context.Response.UpdateNativeResponse(sendHeaders);
1564                 }
1565                 catch {
1566                 }
1567             }
1568
1569             if (sendHeaders) {
1570                 context.FinishPipelineRequest();
1571             }
1572
1573             // Perf optimization: dispose managed context if possible (no need to try if status is pending)
1574             if (status != RequestNotificationStatus.Pending) {
1575                 PipelineRuntime.DisposeHandler(context, requestContext, status);
1576             }
1577         }
1578
1579         internal static void FinishPipelineRequest(HttpContext context) {
1580             // Remember that first request is done
1581             _theRuntime._firstRequestCompleted = true;
1582
1583             // need to raise OnRequestCompleted while within the ThreadContext so that things like User, CurrentCulture, etc. are available
1584             context.RaiseOnRequestCompleted();
1585
1586             context.Request.Dispose();
1587             context.Response.Dispose();
1588             HttpApplication app = context.ApplicationInstance;
1589             if(null != app) {
1590                 ThreadContext threadContext = context.IndicateCompletionContext;
1591                 if (threadContext != null) {
1592                     if (!threadContext.HasBeenDisassociatedFromThread) {
1593                         lock (threadContext) {
1594                             if (!threadContext.HasBeenDisassociatedFromThread) {
1595                                 threadContext.DisassociateFromCurrentThread();
1596                                 context.IndicateCompletionContext = null;
1597                                 context.InIndicateCompletion = false;
1598                             }
1599                         }
1600                     }
1601                 }
1602                 app.ReleaseAppInstance();
1603             }
1604
1605             SetExecutionTimePerformanceCounter(context);
1606             UpdatePerfCounters(context.Response.StatusCode);
1607             if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
1608
1609             // In case of a HostingInit() error, app domain should not stick around
1610             if (HostingInitFailed) {
1611                 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of HostingInit error");
1612                 ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, "HostingInit error");
1613             }
1614         }
1615
1616
1617         /*
1618          * Process one request
1619          */
1620         private void ProcessRequestInternal(HttpWorkerRequest wr) {
1621             // Count active requests
1622             Interlocked.Increment(ref _activeRequestCount);
1623
1624             if (_disposingHttpRuntime) {
1625                 // Dev11 333176: An appdomain is unloaded before all requests are served, resulting in System.AppDomainUnloadedException during isapi completion callback
1626                 //
1627                 // HttpRuntim.Dispose could have already finished on a different thread when we had no active requests
1628                 // In this case we are about to start or already started unloading the appdomain so we will reject the request the safest way possible
1629                 try {
1630                     wr.SendStatus(503, "Server Too Busy");
1631                     wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
1632                     byte[] body = Encoding.ASCII.GetBytes("<html><body>Server Too Busy</body></html>");
1633                     wr.SendResponseFromMemory(body, body.Length);
1634                     // this will flush synchronously because of HttpRuntime.ShutdownInProgress
1635                     wr.FlushResponse(true);
1636                     wr.EndOfRequest();
1637                 } finally {
1638                     Interlocked.Decrement(ref _activeRequestCount);
1639                 }
1640                 return;
1641             }
1642
1643             // Construct the Context on HttpWorkerRequest, hook everything together
1644             HttpContext context;
1645
1646             try {
1647                 context = new HttpContext(wr, false /* initResponseWriter */);
1648             } 
1649             catch {
1650                 try {
1651                     // If we fail to create the context for any reason, send back a 400 to make sure
1652                     // the request is correctly closed (relates to VSUQFE3962)
1653                     wr.SendStatus(400, "Bad Request");
1654                     wr.SendKnownResponseHeader(HttpWorkerRequest.HeaderContentType, "text/html; charset=utf-8");
1655                     byte[] body = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
1656                     wr.SendResponseFromMemory(body, body.Length);
1657                     wr.FlushResponse(true);
1658                     wr.EndOfRequest();
1659                     return;
1660                 } finally {
1661                     Interlocked.Decrement(ref _activeRequestCount);
1662                 }
1663             }
1664
1665             wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
1666
1667             HostingEnvironment.IncrementBusyCount();
1668
1669             try {
1670                 // First request initialization
1671                 try {
1672                     EnsureFirstRequestInit(context);
1673                 }
1674                 catch {
1675                     // If we are handling a DEBUG request, ignore the FirstRequestInit exception.
1676                     // This allows the HttpDebugHandler to execute, and lets the debugger attach to
1677                     // the process (VSWhidbey 358135)
1678                     if (!context.Request.IsDebuggingRequest) {
1679                         throw;
1680                     }
1681                 }
1682
1683                 // Init response writer (after we have config in first request init)
1684                 // no need for impersonation as it is handled in config system
1685                 context.Response.InitResponseWriter();
1686
1687                 // Get application instance
1688                 IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
1689
1690                 if (app == null)
1691                     throw new HttpException(SR.GetString(SR.Unable_create_app_object));
1692
1693                 if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, app.GetType().FullName, "Start");
1694
1695                 if (app is IHttpAsyncHandler) {
1696                     // asynchronous handler
1697                     IHttpAsyncHandler asyncHandler = (IHttpAsyncHandler)app;
1698                     context.AsyncAppHandler = asyncHandler;
1699                     asyncHandler.BeginProcessRequest(context, _handlerCompletionCallback, context);
1700                 }
1701                 else {
1702                     // synchronous handler
1703                     app.ProcessRequest(context);
1704                     FinishRequest(context.WorkerRequest, context, null);
1705                 }
1706             }
1707             catch (Exception e) {
1708                 context.Response.InitResponseWriter();
1709                 FinishRequest(wr, context, e);
1710             }
1711         }
1712
1713         private void RejectRequestInternal(HttpWorkerRequest wr, bool silent) {
1714             // Construct the Context on HttpWorkerRequest, hook everything together
1715             HttpContext context = new HttpContext(wr, false /* initResponseWriter */);
1716             wr.SetEndOfSendNotification(_asyncEndOfSendCallback, context);
1717
1718             // Count active requests
1719             Interlocked.Increment(ref _activeRequestCount);
1720             HostingEnvironment.IncrementBusyCount();
1721
1722             if (silent) {
1723                 context.Response.InitResponseWriter();
1724                 FinishRequest(wr, context, null);
1725             }
1726             else {
1727                 PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.REQUESTS_REJECTED);
1728                 PerfCounters.IncrementCounter(AppPerfCounter.APP_REQUESTS_REJECTED);
1729                 try {
1730                     throw new HttpException(503, SR.GetString(SR.Server_too_busy));
1731                 }
1732                 catch (Exception e) {
1733                     context.Response.InitResponseWriter();
1734                     FinishRequest(wr, context, e);
1735                 }
1736             }
1737         }
1738
1739         internal static void ReportAppOfflineErrorMessage(HttpResponse response, byte[] appOfflineMessage) {
1740             response.StatusCode = 503;
1741             response.ContentType = "text/html";
1742             response.AddHeader("Retry-After", "3600");
1743             response.OutputStream.Write(appOfflineMessage, 0, appOfflineMessage.Length);
1744         }
1745
1746         /*
1747          * Finish processing request, sync or async
1748          */
1749         private void FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) {
1750             HttpResponse response = context.Response;
1751
1752             if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Verbose, EtwTraceFlags.Infrastructure)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_END_HANDLER, context.WorkerRequest);
1753
1754             SetExecutionTimePerformanceCounter(context);
1755
1756             // Flush in case of no error
1757             if (e == null) {
1758                 // impersonate around PreSendHeaders / PreSendContent
1759                 using (new ClientImpersonationContext(context, false)) {
1760                     try {
1761                         // this sends the actual content in most cases
1762                         response.FinalFlushAtTheEndOfRequestProcessing();
1763                     }
1764                     catch (Exception eFlush) {
1765                         e = eFlush;
1766                     }
1767                 }
1768             }
1769
1770             // Report error if any
1771             if (e != null) {
1772                 using (new DisposableHttpContextWrapper(context)) {
1773
1774                     // if the custom encoder throws, it might interfere with returning error information
1775                     // to the client, so we force use of the default encoder
1776                     context.DisableCustomHttpEncoder = true;
1777
1778                     if (_appOfflineMessage != null) {
1779                         try {
1780                             ReportAppOfflineErrorMessage(response, _appOfflineMessage);
1781                             response.FinalFlushAtTheEndOfRequestProcessing();
1782                         }
1783                         catch {
1784                         }
1785                     }
1786                     else {
1787                         // when application is on UNC share the code below must
1788                         // be run while impersonating the token given by IIS
1789                         using (new ApplicationImpersonationContext()) {
1790                             try {
1791                                 try {
1792                                     // try to report error in a way that could possibly throw (a config exception)
1793                                     response.ReportRuntimeError(e, true /*canThrow*/, false);
1794                                 }
1795                                 catch (Exception eReport) {
1796                                     // report the config error in a way that would not throw
1797                                     response.ReportRuntimeError(eReport, false /*canThrow*/, false);
1798                                 }
1799
1800                                 response.FinalFlushAtTheEndOfRequestProcessing();
1801                             }
1802                             catch {
1803                             }
1804                         }
1805                     }
1806                 }
1807             }
1808
1809             // Remember that first request is done
1810             _firstRequestCompleted = true;
1811
1812
1813             // In case we reporting HostingInit() error, app domain should not stick around
1814             if (_hostingInitFailed) {
1815                 Debug.Trace("AppDomainFactory", "Shutting down appdomain because of HostingInit error");
1816                 ShutdownAppDomain(ApplicationShutdownReason.HostingEnvironment, "HostingInit error");
1817             }
1818
1819             // Check status code and increment proper counter
1820             // If it's an error status code (i.e. 400 or higher), increment the proper perf counters
1821             int statusCode = response.StatusCode;
1822             UpdatePerfCounters(statusCode);
1823
1824             context.FinishRequestForCachedPathData(statusCode);
1825
1826             // ---- exceptions from EndOfRequest as they will prevent proper request cleanup
1827             // Since the exceptions are not expected here we want to log them
1828             try {
1829                 wr.EndOfRequest();
1830             }
1831             catch (Exception ex) {
1832                 WebBaseEvent.RaiseRuntimeError(ex, this);
1833             }
1834
1835             // Count active requests
1836             HostingEnvironment.DecrementBusyCount();
1837             Interlocked.Decrement(ref _activeRequestCount);
1838
1839             // Schedule more work if some requests are queued
1840             if (_requestQueue != null)
1841                 _requestQueue.ScheduleMoreWorkIfNeeded();
1842         }
1843
1844         //
1845         // Make sure shutdown happens only once
1846         //
1847
1848         private bool InitiateShutdownOnce() {
1849             if (_shutdownInProgress)
1850                 return false;
1851
1852             lock (this) {
1853                 if (_shutdownInProgress)
1854                     return false;
1855                 _shutdownInProgress = true;
1856             }
1857
1858             return true;
1859         }
1860
1861         //
1862         // Shutdown this and restart new app domain
1863         //
1864         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
1865         private void ReleaseResourcesAndUnloadAppDomain(Object state /*not used*/) {
1866 #if DBG
1867             Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
1868                         "*** ReleaseResourcesAndUnloadAppDomain " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
1869                         + ": _appDomainAppId=" + _appDomainAppId);
1870 #endif
1871             Debug.Trace("AppDomainFactory", "ReleaseResourcesAndUnloadAppDomain, Id=" + _appDomainAppId
1872                         + " DomainId = " + _appDomainId
1873                         + " Stack = " + Environment.StackTrace );
1874
1875             try {
1876                 PerfCounters.IncrementGlobalCounter(GlobalPerfCounter.APPLICATION_RESTARTS);
1877             }
1878             catch {
1879             }
1880
1881             // Release all resources
1882             try {
1883                 Dispose();
1884             }
1885             catch {
1886             }
1887
1888             Thread.Sleep(250);
1889
1890             AddAppDomainTraceMessage("before Unload");
1891
1892             for (; ; ) {
1893                 try {
1894                     AppDomain.Unload(Thread.GetDomain());
1895                 }
1896                 catch (CannotUnloadAppDomainException) {
1897                     Debug.Assert(false);
1898                 }
1899                 catch (Exception e) {
1900                     Debug.Trace("AppDomainFactory", "AppDomain.Unload exception: " + e + "; Id=" + _appDomainAppId);
1901                     if (!BuildManagerHost.InClientBuildManager) {
1902                         // Avoid calling Exception.ToString if we are in the ClientBuildManager (Dev10 
1903                         AddAppDomainTraceMessage("Unload Exception: " + e);
1904                     }
1905                     throw;
1906                 }
1907             }
1908         }
1909
1910         private static void SetExecutionTimePerformanceCounter(HttpContext context) {
1911             // Set the Request Execution time perf counter
1912             TimeSpan elapsed = DateTime.UtcNow.Subtract(context.WorkerRequest.GetStartTime());
1913             long milli = elapsed.Ticks / TimeSpan.TicksPerMillisecond;
1914
1915             if (milli > Int32.MaxValue)
1916                 milli = Int32.MaxValue;
1917
1918             PerfCounters.SetGlobalCounter(GlobalPerfCounter.REQUEST_EXECUTION_TIME, (int)milli);
1919             PerfCounters.SetCounter(AppPerfCounter.APP_REQUEST_EXEC_TIME, (int)milli);
1920         }
1921
1922         private static void UpdatePerfCounters(int statusCode) {
1923             if (400 <= statusCode) {
1924                 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_FAILED);
1925                 switch (statusCode) {
1926                     case 401: // Not authorized
1927                         PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_AUTHORIZED);
1928                         break;
1929                     case 404: // Not found
1930                     case 414: // Not found
1931                         PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_NOT_FOUND);
1932                         break;
1933                 }
1934             }
1935             else {
1936                 // If status code is not in the 400-599 range (i.e. 200-299 success or 300-399 redirection),
1937                 // count it as a successful request.
1938                 PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_SUCCEDED);
1939             }
1940         }
1941
1942         private void WaitForRequestsToFinish(int waitTimeoutMs) {
1943             DateTime waitLimit = DateTime.UtcNow.AddMilliseconds(waitTimeoutMs);
1944
1945             for (; ; ) {
1946                 if (_activeRequestCount == 0 && (_requestQueue == null || _requestQueue.IsEmpty))
1947                     break;
1948
1949                 Thread.Sleep(250);
1950
1951                 // only apply timeout if a managed debugger is not attached
1952                 if (!System.Diagnostics.Debugger.IsAttached && DateTime.UtcNow > waitLimit) {
1953                     break; // give it up
1954                 }
1955             }
1956         }
1957
1958         /*
1959          * Cleanup of all unmananged state
1960          */
1961         private void Dispose() {
1962             // get shutdown timeout from config
1963             int drainTimeoutSec = HttpRuntimeSection.DefaultShutdownTimeout;
1964             try {
1965                 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetAppLKGConfig().HttpRuntime;
1966                 if (runtimeConfig != null) {
1967                     drainTimeoutSec = (int)runtimeConfig.ShutdownTimeout.TotalSeconds;
1968                 }
1969
1970                 // before aborting compilation give time to drain (new requests are no longer coming at this point)
1971                 WaitForRequestsToFinish(drainTimeoutSec * 1000);
1972
1973                 // reject remaining queued requests
1974                 if (_requestQueue != null)
1975                     _requestQueue.Drain();
1976             } finally {
1977                 // By this time all new requests should be directed to a newly created app domain
1978                 // But there might be requests that got dispatched to this old app domain but have not reached ProcessRequestInternal yet
1979                 // Signal ProcessRequestInternal to reject them immediately without initiating async operations
1980                 _disposingHttpRuntime = true;
1981             }
1982
1983             // give it a little more time to drain
1984             WaitForRequestsToFinish((drainTimeoutSec * 1000) / 6);
1985
1986
1987             // wait for pending async io to complete,  prior to aborting requests
1988             // this isn't necessary for IIS 7, where the async sends are always done
1989             // from native code with native buffers
1990             System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.WaitForPendingAsyncIo();
1991
1992             // For IIS7 integrated pipeline, wait until GL_APPLICATION_STOP fires and
1993             // there are no active calls to IndicateCompletion before unloading the AppDomain
1994             if (HttpRuntime.UseIntegratedPipeline) {
1995                 PipelineRuntime.WaitForRequestsToDrain();
1996             }
1997             else {
1998                 // wait for all active requests to complete
1999                 while (_activeRequestCount != 0) {
2000                     Thread.Sleep(250);
2001                 }
2002             }
2003
2004
2005             // Dispose AppDomainShutdownTimer
2006             DisposeAppDomainShutdownTimer();
2007
2008             // kill all remaining requests (and the timeout timer)
2009             _timeoutManager.Stop();
2010             AppDomainResourcePerfCounters.Stop();                 
2011
2012 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
2013             // double check for pending async io
2014             System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6.WaitForPendingAsyncIo();
2015
2016             // stop sqlcachedependency polling
2017             SqlCacheDependencyManager.Dispose((drainTimeoutSec * 1000) / 2);
2018 #endif // !FEATURE_PAL
2019             // cleanup cache (this ends all sessions)
2020             if (_cacheInternal != null) {
2021                 _cacheInternal.Dispose();
2022             }
2023
2024             // app on end, cleanup app instances
2025             HttpApplicationFactory.EndApplication();  // call app_onEnd
2026
2027             // stop file changes monitor
2028             _fcm.Stop();
2029
2030             // stop health monitoring timer
2031             HealthMonitoringManager.Shutdown();
2032         }
2033
2034         /*
2035          * Async completion of IIS7 pipeline (unlike OnHandlerCompletion, this may fire more than once).
2036          */
2037         private void OnRequestNotificationCompletion(IAsyncResult ar) {
2038             try {
2039                 OnRequestNotificationCompletionHelper(ar);
2040             }
2041             catch(Exception e) {
2042                 ApplicationManager.RecordFatalException(e);
2043                 throw;
2044             }
2045         }
2046
2047         private void OnRequestNotificationCompletionHelper(IAsyncResult ar) {
2048             if (ar.CompletedSynchronously) {
2049                 Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion: completed synchronously");
2050                 return;
2051             }
2052
2053             Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion: completed asynchronously");
2054
2055             RequestNotificationStatus status = RequestNotificationStatus.Continue;
2056             HttpContext context = (HttpContext) ar.AsyncState;
2057             IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
2058
2059             try {
2060                 context.ApplicationInstance.EndProcessRequestNotification(ar);
2061             }
2062             catch (Exception e) {
2063                 status = RequestNotificationStatus.FinishRequest;
2064                 context.AddError(e);
2065             }
2066
2067             // RequestContext is set to null if this is the last notification, so we need to save it
2068             // for the call to PostCompletion
2069             IntPtr requestContext = wr.RequestContext;
2070
2071             FinishRequestNotification(wr, context, ref status);
2072
2073             // set the notification context to null since we are exiting this notification
2074             context.NotificationContext = null;
2075
2076             // Indicate completion to IIS, so that it can resume
2077             // request processing on an IIS thread
2078             Debug.Trace("PipelineRuntime", "OnRequestNotificationCompletion(" + status + ")");
2079             int result = UnsafeIISMethods.MgdPostCompletion(requestContext, status);
2080             Misc.ThrowIfFailedHr(result);
2081         }
2082
2083         /*
2084          * Async completion of managed pipeline (called at most one time).
2085          */
2086         private void OnHandlerCompletion(IAsyncResult ar) {
2087             HttpContext context = (HttpContext)ar.AsyncState;
2088
2089             try {
2090                 context.AsyncAppHandler.EndProcessRequest(ar);
2091             }
2092             catch (Exception e) {
2093                 context.AddError(e);
2094             }
2095             finally {
2096                 // no longer keep AsyncAppHandler poiting to the application
2097                 // is only needed to call EndProcessRequest
2098                 context.AsyncAppHandler = null;
2099             }
2100
2101             FinishRequest(context.WorkerRequest, context, context.Error);
2102         }
2103
2104         /*
2105          * Notification from worker request that it is done writing from buffer
2106          * so that the buffers can be recycled
2107          */
2108         private void EndOfSendCallback(HttpWorkerRequest wr, Object arg) {
2109             Debug.Trace("PipelineRuntime", "HttpRuntime.EndOfSendCallback");
2110             HttpContext context = (HttpContext)arg;
2111             context.Request.Dispose();
2112             context.Response.Dispose();
2113         }
2114
2115         /*
2116          * Notification when something in the bin directory changed
2117          */
2118         private void OnCriticalDirectoryChange(Object sender, FileChangeEvent e) {
2119             // shutdown the app domain
2120             Debug.Trace("AppDomainFactory", "Shutting down appdomain because of bin dir change or directory rename." +
2121                 " FileName=" + e.FileName + " Action=" + e.Action);
2122
2123             ApplicationShutdownReason reason = ApplicationShutdownReason.None;
2124             string directoryName = new DirectoryInfo(e.FileName).Name;
2125
2126             string message = FileChangesMonitor.GenerateErrorMessage(e.Action);
2127             message = (message != null) ? message + directoryName : directoryName + " dir change or directory rename";
2128
2129             if (StringUtil.EqualsIgnoreCase(directoryName, CodeDirectoryName)) {
2130                 reason = ApplicationShutdownReason.CodeDirChangeOrDirectoryRename;
2131             }
2132             else if (StringUtil.EqualsIgnoreCase(directoryName, ResourcesDirectoryName)) {
2133                 reason = ApplicationShutdownReason.ResourcesDirChangeOrDirectoryRename;
2134             }
2135             else if (StringUtil.EqualsIgnoreCase(directoryName, BrowsersDirectoryName)) {
2136                 reason = ApplicationShutdownReason.BrowsersDirChangeOrDirectoryRename;
2137             }
2138             else if (StringUtil.EqualsIgnoreCase(directoryName, BinDirectoryName)) {
2139                 reason = ApplicationShutdownReason.BinDirChangeOrDirectoryRename;
2140             }
2141
2142             if (e.Action == FileAction.Added) {
2143                 // Make sure HttpRuntime does not ignore the appdomain shutdown if a file is added (VSWhidbey 363481)
2144                 HttpRuntime.SetUserForcedShutdown();
2145
2146                 Debug.Trace("AppDomainFactorySpecial", "Call SetUserForcedShutdown: FileName=" + e.FileName + "; now=" + DateTime.Now);
2147             }
2148
2149             ShutdownAppDomain(reason, message);
2150         }
2151
2152         /**
2153          * Coalesce file change notifications to minimize sharing violations and AppDomain restarts (ASURT 147492)
2154          */
2155         internal static void CoalesceNotifications() {
2156             int waitChangeNotification = HttpRuntimeSection.DefaultWaitChangeNotification;
2157             int maxWaitChangeNotification = HttpRuntimeSection.DefaultMaxWaitChangeNotification;
2158             try {
2159                 HttpRuntimeSection config = RuntimeConfig.GetAppLKGConfig().HttpRuntime;
2160                 if (config != null) {
2161                     waitChangeNotification = config.WaitChangeNotification;
2162                     maxWaitChangeNotification = config.MaxWaitChangeNotification;
2163                 }
2164             }
2165             catch {
2166             }
2167
2168             if (waitChangeNotification == 0 || maxWaitChangeNotification == 0)
2169                 return;
2170
2171             DateTime maxWait = DateTime.UtcNow.AddSeconds(maxWaitChangeNotification);
2172             // Coalesce file change notifications
2173             try {
2174                 while (DateTime.UtcNow < maxWait) {
2175                     if (DateTime.UtcNow > _theRuntime.LastShutdownAttemptTime.AddSeconds(waitChangeNotification))
2176                         break;
2177
2178                     Thread.Sleep(250);
2179                 }
2180             }
2181             catch {
2182             }
2183         }
2184
2185         // appdomain shutdown eventhandler
2186         internal static event BuildManagerHostUnloadEventHandler AppDomainShutdown;
2187
2188         internal static void OnAppDomainShutdown(BuildManagerHostUnloadEventArgs e) {
2189             if (AppDomainShutdown != null) {
2190                 AppDomainShutdown(_theRuntime, e);
2191             }
2192         }
2193
2194         internal static void SetUserForcedShutdown() {
2195             _theRuntime._userForcedShutdown = true;
2196         }
2197
2198         /*
2199          * Shutdown the current app domain
2200          */
2201         internal static bool ShutdownAppDomain(ApplicationShutdownReason reason, string message) {
2202             return ShutdownAppDomainWithStackTrace(reason, message, null /*stackTrace*/);
2203         }
2204
2205         /*
2206          * Shutdown the current app domain with a stack trace.  This is useful for callers that are running
2207          * on a QUWI callback, and wouldn't provide a meaningful stack trace by default.
2208          */
2209         internal static bool ShutdownAppDomainWithStackTrace(ApplicationShutdownReason reason, string message, string stackTrace) {
2210             SetShutdownReason(reason, message);
2211             return ShutdownAppDomain(stackTrace);
2212         }
2213
2214         private static bool ShutdownAppDomain(string stackTrace) {
2215 #if DBG
2216             Debug.Trace("FileChangesMonitorIgnoreSubdirChange",
2217                         "*** ShutdownAppDomain " + DateTime.Now.ToString("hh:mm:ss.fff", CultureInfo.InvariantCulture)
2218                         + ": _appDomainAppId=" + HttpRuntime.AppDomainAppId);
2219 #endif
2220             // Ignore notifications during the processing of the first request (ASURT 100335)
2221             // skip this if LastShutdownAttemptTime has been set
2222             if (_theRuntime.LastShutdownAttemptTime == DateTime.MinValue && !_theRuntime._firstRequestCompleted && !_theRuntime._userForcedShutdown) {
2223                 // check the timeout (don't disable notifications forever
2224                 int delayTimeoutSec = HttpRuntimeSection.DefaultDelayNotificationTimeout;
2225
2226                 try {
2227                     RuntimeConfig runtimeConfig = RuntimeConfig.GetAppLKGConfig();
2228                     if (runtimeConfig != null) {
2229                         HttpRuntimeSection runtimeSection = runtimeConfig.HttpRuntime;
2230                         if (runtimeSection != null) {
2231                             delayTimeoutSec = (int)runtimeSection.DelayNotificationTimeout.TotalSeconds;
2232
2233                             if (DateTime.UtcNow < _theRuntime._firstRequestStartTime.AddSeconds(delayTimeoutSec)) {
2234                                 Debug.Trace("AppDomainFactory", "ShutdownAppDomain IGNORED (1st request is not done yet), Id = " + AppDomainAppId);
2235                                 return false;
2236                             }
2237                         }
2238                     }
2239                 }
2240                 catch {
2241                 }
2242             }
2243
2244             try {
2245                 _theRuntime.RaiseShutdownWebEventOnce();
2246             }
2247             catch {
2248                 // VSWhidbey 444472: if an exception is thrown, we consume it and continue executing the following code.
2249             }
2250
2251             // Update last time ShutdownAppDomain was called
2252             _theRuntime.LastShutdownAttemptTime = DateTime.UtcNow;
2253
2254             if (!HostingEnvironment.ShutdownInitiated) {
2255                 // This shutdown is not triggered by hosting environment - let it do the job
2256                 HostingEnvironment.InitiateShutdownWithoutDemand();
2257                 return true;
2258             }
2259
2260             //WOS 1400290: CantUnloadAppDomainException in ISAPI mode, wait until HostingEnvironment.ShutdownThisAppDomainOnce completes
2261             if (HostingEnvironment.ShutdownInProgress) {
2262                 return false;
2263             }
2264
2265             // Make sure we don't go through shutdown logic many times
2266             if (!_theRuntime.InitiateShutdownOnce())
2267                 return false;
2268
2269             Debug.Trace("AppDomainFactory", "ShutdownAppDomain, Id = " + AppDomainAppId + ", ShutdownInProgress=" + ShutdownInProgress
2270                         + ", ShutdownMessage=" + _theRuntime._shutDownMessage);
2271
2272             if (String.IsNullOrEmpty(stackTrace) && !BuildManagerHost.InClientBuildManager) {
2273                 // Avoid calling Environment.StackTrace if we are in the ClientBuildManager (Dev10 
2274
2275                 // Instrument to be able to see what's causing a shutdown
2276                 new EnvironmentPermission(PermissionState.Unrestricted).Assert();
2277                 try {
2278                     _theRuntime._shutDownStack = Environment.StackTrace;
2279                 }
2280                 finally {
2281                     CodeAccessPermission.RevertAssert();
2282                 }
2283             }
2284             else {
2285                 _theRuntime._shutDownStack = stackTrace;
2286             }
2287
2288             // Notify when appdomain is about to shutdown.
2289             OnAppDomainShutdown(new BuildManagerHostUnloadEventArgs(_theRuntime._shutdownReason));
2290
2291             // unload app domain from another CLR thread
2292             ThreadPool.QueueUserWorkItem(_theRuntime._appDomainUnloadallback);
2293
2294             return true;
2295         }
2296
2297         internal static void RecoverFromUnexceptedAppDomainUnload() {
2298             if (_theRuntime._shutdownInProgress)
2299                 return;
2300
2301             // someone unloaded app domain directly - tell unmanaged code
2302             Debug.Trace("AppDomainFactory", "Unexpected AppDomainUnload");
2303             _theRuntime._shutdownInProgress = true;
2304
2305             // tell unmanaged code not to dispatch requests to this app domain
2306             try {
2307                 ISAPIRuntime.RemoveThisAppDomainFromUnmanagedTable();
2308                 PipelineRuntime.RemoveThisAppDomainFromUnmanagedTable();
2309                 AddAppDomainTraceMessage("AppDomainRestart");
2310             }
2311             finally {
2312                 // release all resources
2313                 _theRuntime.Dispose();
2314             }
2315         }
2316
2317         /*
2318          * Notification when app-level Config changed
2319          */
2320          internal static void OnConfigChange(String message) {
2321             Debug.Trace("AppDomainFactory", "Shutting down appdomain because of config change");
2322             ShutdownAppDomain(ApplicationShutdownReason.ConfigurationChange, (message != null) ? message : "CONFIG change");
2323         }
2324
2325         // Intrumentation to remember the overwhelming file change
2326         internal static void SetShutdownReason(ApplicationShutdownReason reason, String message) {
2327             if (_theRuntime._shutdownReason == ApplicationShutdownReason.None) {
2328                 _theRuntime._shutdownReason = reason;
2329             }
2330
2331             SetShutdownMessage(message);
2332         }
2333
2334         internal static void SetShutdownMessage(String message) {
2335             if (message != null) {
2336                 if (_theRuntime._shutDownMessage == null)
2337                     _theRuntime._shutDownMessage = message;
2338                 else
2339                     _theRuntime._shutDownMessage += "\r\n" + message;
2340             }
2341         }
2342
2343
2344         // public method is on HostingEnvironment
2345         internal static ApplicationShutdownReason ShutdownReason {
2346             get { return _theRuntime._shutdownReason; }
2347         }
2348
2349         //
2350         // public static APIs
2351         //
2352
2353         /*
2354          * Process one request
2355          */
2356
2357         /// <devdoc>
2358         ///    <para><SPAN>The method that drives
2359         ///       all ASP.NET web processing execution.</SPAN></para>
2360         /// </devdoc>
2361         [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
2362         public static void ProcessRequest(HttpWorkerRequest wr) {
2363             if (wr == null)
2364                 throw new ArgumentNullException("wr");
2365
2366             if (HttpRuntime.UseIntegratedPipeline) {
2367                 throw new PlatformNotSupportedException(SR.GetString(SR.Method_Not_Supported_By_Iis_Integrated_Mode, "HttpRuntime.ProcessRequest"));
2368             }
2369
2370             ProcessRequestNoDemand(wr);
2371         }
2372
2373
2374         internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) {
2375             RequestQueue rq = _theRuntime._requestQueue;
2376
2377             wr.UpdateInitialCounters();
2378
2379             if (rq != null)  // could be null before first request
2380                 wr = rq.GetRequestToExecute(wr);
2381
2382             if (wr != null) {
2383                 CalculateWaitTimeAndUpdatePerfCounter(wr);
2384                 wr.ResetStartTime();
2385                 ProcessRequestNow(wr);
2386             }
2387         }
2388
2389
2390         private static void CalculateWaitTimeAndUpdatePerfCounter(HttpWorkerRequest wr) {
2391             DateTime begin = wr.GetStartTime();
2392
2393             TimeSpan elapsed = DateTime.UtcNow.Subtract(begin);
2394             long milli = elapsed.Ticks / TimeSpan.TicksPerMillisecond;
2395
2396             if (milli > Int32.MaxValue)
2397                 milli = Int32.MaxValue;
2398
2399             PerfCounters.SetGlobalCounter(GlobalPerfCounter.REQUEST_WAIT_TIME, (int)milli);
2400             PerfCounters.SetCounter(AppPerfCounter.APP_REQUEST_WAIT_TIME, (int)milli);
2401         }
2402
2403         internal static void ProcessRequestNow(HttpWorkerRequest wr) {
2404             _theRuntime.ProcessRequestInternal(wr);
2405         }
2406
2407         internal static void RejectRequestNow(HttpWorkerRequest wr, bool silent) {
2408             _theRuntime.RejectRequestInternal(wr, silent);
2409         }
2410
2411
2412         /// <devdoc>
2413         ///       <para>Removes all items from the cache and shuts down the runtime.</para>
2414         ///    </devdoc>
2415         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
2416         public static void Close() {
2417             Debug.Trace("AppDomainFactory", "HttpRuntime.Close, ShutdownInProgress=" + ShutdownInProgress);
2418             if (_theRuntime.InitiateShutdownOnce()) {
2419                 SetShutdownReason(ApplicationShutdownReason.HttpRuntimeClose, "HttpRuntime.Close is called");
2420
2421                 if (HostingEnvironment.IsHosted) {
2422                     // go throw initiate shutdown for hosted scenarios
2423                     HostingEnvironment.InitiateShutdownWithoutDemand();
2424                 }
2425                 else {
2426                     _theRuntime.Dispose();
2427                 }
2428             }
2429         }
2430
2431
2432         /// <devdoc>
2433         ///       <para>Unloads the current app domain.</para>
2434         ///    </devdoc>
2435         public static void UnloadAppDomain() {
2436             _theRuntime._userForcedShutdown = true;
2437             ShutdownAppDomain(ApplicationShutdownReason.UnloadAppDomainCalled, "User code called UnloadAppDomain");
2438         }
2439
2440         private DateTime LastShutdownAttemptTime {
2441             get {
2442                 DateTime dt;
2443                 lock (this) {
2444                     dt = _lastShutdownAttemptTime;
2445                 }
2446                 return dt;
2447             }
2448             set {
2449                 lock (this) {
2450                     _lastShutdownAttemptTime = value;
2451                 }
2452             }
2453         }
2454
2455         internal static Profiler Profile {
2456             get {
2457                 return _theRuntime._profiler;
2458             }
2459         }
2460
2461         internal static bool IsTrustLevelInitialized {
2462             get {
2463                 return !HostingEnvironment.IsHosted || TrustLevel != null;
2464             }
2465         }
2466
2467         internal static NamedPermissionSet NamedPermissionSet {
2468             get {
2469                 // Make sure we have already initialized the trust level
2470                 // 
2471
2472
2473                 return _theRuntime._namedPermissionSet;
2474             }
2475         }
2476
2477         internal static PolicyLevel PolicyLevel {
2478             get {
2479                 return _theRuntime._policyLevel;
2480             }
2481         }
2482
2483         internal static string HostSecurityPolicyResolverType {
2484             get {
2485                 return _theRuntime._hostSecurityPolicyResolverType;
2486             }
2487         }
2488
2489         [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Unrestricted)]
2490         public static NamedPermissionSet GetNamedPermissionSet() {
2491             NamedPermissionSet namedPermissionSet = _theRuntime._namedPermissionSet;
2492             if (namedPermissionSet == null) {
2493                 return null;
2494             }
2495             else {
2496                 return new NamedPermissionSet(namedPermissionSet);
2497             }
2498         }
2499
2500         internal static bool IsFullTrust {
2501             get {
2502                 // Make sure we have already initialized the trust level
2503                 Debug.Assert(IsTrustLevelInitialized);
2504
2505                 return (_theRuntime._namedPermissionSet == null);
2506             }
2507         }
2508
2509         /*
2510          * Check that the current trust level allows access to a virtual path.  Throw if it doesn't,
2511          */
2512         internal static void CheckVirtualFilePermission(string virtualPath) {
2513             string physicalPath = HostingEnvironment.MapPath(virtualPath);
2514             CheckFilePermission(physicalPath);
2515         }
2516
2517         /*
2518          * Check that the current trust level allows access to a path.  Throw if it doesn't,
2519          */
2520         internal static void CheckFilePermission(string path) {
2521             CheckFilePermission(path, false);
2522         }
2523
2524         internal static void CheckFilePermission(string path, bool writePermissions) {
2525             if (!HasFilePermission(path, writePermissions)) {
2526                 throw new HttpException(SR.GetString(SR.Access_denied_to_path, GetSafePath(path)));
2527             }
2528         }
2529
2530         internal static bool HasFilePermission(string path) {
2531             return HasFilePermission(path, false);
2532         }
2533
2534         internal static bool HasFilePermission(string path, bool writePermissions) {
2535             // WOS #1523618: need to skip this check for HttpResponse.ReportRuntimeError when reporting an
2536             // InitializationException (e.g., necessary to display line info for ConfigurationException).
2537
2538             if (TrustLevel == null && InitializationException != null) {
2539                 return true;
2540             }
2541
2542             // Make sure we have already initialized the trust level
2543             Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted, "TrustLevel != null || !HostingEnvironment.IsHosted");
2544
2545             // If we don't have a NamedPermissionSet, we're in full trust
2546             if (NamedPermissionSet == null)
2547                 return true;
2548
2549             bool fAccess = false;
2550
2551             // Check that the user has permission to the path
2552             IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(FileIOPermission));
2553             if (allowedPermission != null) {
2554                 IPermission askedPermission = null;
2555                 try {
2556                     if (!writePermissions)
2557                         askedPermission = new FileIOPermission(FileIOPermissionAccess.Read, path);
2558                     else
2559                         askedPermission = new FileIOPermission(FileIOPermissionAccess.AllAccess, path);
2560                 }
2561                 catch {
2562                     // This could happen if the path is not absolute
2563                     return false;
2564                 }
2565                 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2566             }
2567
2568             return fAccess;
2569         }
2570
2571         internal static bool HasWebPermission(Uri uri) {
2572
2573             // Make sure we have already initialized the trust level
2574             Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2575
2576             // If we don't have a NamedPermissionSet, we're in full trust
2577             if (NamedPermissionSet == null)
2578                 return true;
2579
2580             bool fAccess = false;
2581
2582             // Check that the user has permission to the URI
2583             IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(WebPermission));
2584             if (allowedPermission != null) {
2585                 IPermission askedPermission = null;
2586                 try {
2587                     askedPermission = new WebPermission(NetworkAccess.Connect, uri.ToString());
2588                 }
2589                 catch {
2590                     return false;
2591                 }
2592                 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2593             }
2594
2595             return fAccess;
2596         }
2597
2598         internal static bool HasDbPermission(DbProviderFactory factory) {
2599
2600             // Make sure we have already initialized the trust level
2601             Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2602
2603             // If we don't have a NamedPermissionSet, we're in full trust
2604             if (NamedPermissionSet == null)
2605                 return true;
2606
2607             bool fAccess = false;
2608
2609             // Check that the user has permission to the provider
2610             CodeAccessPermission askedPermission = factory.CreatePermission(PermissionState.Unrestricted);
2611             if (askedPermission != null) {
2612                 IPermission allowedPermission = NamedPermissionSet.GetPermission(askedPermission.GetType());
2613                 if (allowedPermission != null) {
2614                     fAccess = askedPermission.IsSubsetOf(allowedPermission);
2615                 }
2616             }
2617
2618             return fAccess;
2619         }
2620
2621         internal static bool HasPathDiscoveryPermission(string path) {
2622             // WOS #1523618: need to skip this check for HttpResponse.ReportRuntimeError when reporting an
2623             // InitializationException (e.g., necessary to display line info for ConfigurationException).
2624
2625             if (TrustLevel == null && InitializationException != null) {
2626                 return true;
2627             }
2628
2629             // Make sure we have already initialized the trust level
2630             Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2631
2632             // If we don't have a NamedPermissionSet, we're in full trust
2633             if (NamedPermissionSet == null)
2634                 return true;
2635
2636             bool fAccess = false;
2637
2638             // Check that the user has permission to the path
2639             IPermission allowedPermission = NamedPermissionSet.GetPermission(typeof(FileIOPermission));
2640             if (allowedPermission != null) {
2641                 IPermission askedPermission = new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path);
2642                 fAccess = askedPermission.IsSubsetOf(allowedPermission);
2643             }
2644
2645             return fAccess;
2646
2647         }
2648
2649         internal static bool HasAppPathDiscoveryPermission() {
2650             return HasPathDiscoveryPermission(HttpRuntime.AppDomainAppPathInternal);
2651         }
2652
2653         internal static string GetSafePath(string path) {
2654             if (String.IsNullOrEmpty(path))
2655                 return path;
2656
2657             try {
2658                 if (HasPathDiscoveryPermission(path)) // could throw on bad filenames
2659                     return path;
2660             }
2661             catch {
2662             }
2663
2664             return Path.GetFileName(path);
2665         }
2666
2667         /*
2668          * Check that the current trust level allows Unmanaged access
2669          */
2670         internal static bool HasUnmanagedPermission() {
2671
2672             // Make sure we have already initialized the trust level
2673             Debug.Assert(TrustLevel != null || !HostingEnvironment.IsHosted);
2674
2675             // If we don't have a NamedPermissionSet, we're in full trust
2676             if (NamedPermissionSet == null)
2677                 return true;
2678
2679             SecurityPermission securityPermission = (SecurityPermission)NamedPermissionSet.GetPermission(
2680                 typeof(SecurityPermission));
2681             if (securityPermission == null)
2682                 return false;
2683
2684             return (securityPermission.Flags & SecurityPermissionFlag.UnmanagedCode) != 0;
2685         }
2686
2687         internal static bool HasAspNetHostingPermission(AspNetHostingPermissionLevel level) {
2688
2689             // Make sure we have already initialized the trust level
2690             // 
2691
2692
2693
2694             // If we don't have a NamedPermissionSet, we're in full trust
2695             if (NamedPermissionSet == null)
2696                 return true;
2697
2698             AspNetHostingPermission permission = (AspNetHostingPermission)NamedPermissionSet.GetPermission(
2699                 typeof(AspNetHostingPermission));
2700             if (permission == null)
2701                 return false;
2702
2703             return (permission.Level >= level);
2704         }
2705
2706         internal static void CheckAspNetHostingPermission(AspNetHostingPermissionLevel level, String errorMessageId) {
2707             if (!HasAspNetHostingPermission(level)) {
2708                 throw new HttpException(SR.GetString(errorMessageId));
2709             }
2710         }
2711
2712         // If we're not in full trust, fail if the passed in type doesn't have the APTCA bit
2713         internal static void FailIfNoAPTCABit(Type t, ElementInformation elemInfo, string propertyName) {
2714
2715             if (!IsTypeAllowedInConfig(t)) {
2716                 if (null != elemInfo) {
2717                     PropertyInformation propInfo = elemInfo.Properties[propertyName];
2718
2719                     throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName),
2720                     propInfo.Source, propInfo.LineNumber);
2721                 }
2722                 else {
2723                     throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName));
2724                 }
2725             }
2726         }
2727
2728         // If we're not in full trust, fail if the passed in type doesn't have the APTCA bit
2729         internal static void FailIfNoAPTCABit(Type t, XmlNode node) {
2730
2731             if (!IsTypeAllowedInConfig(t)) {
2732                 throw new ConfigurationErrorsException(SR.GetString(SR.Type_from_untrusted_assembly, t.FullName),
2733                     node);
2734             }
2735         }
2736
2737         private static bool HasAPTCABit(Assembly assembly) {
2738             return assembly.IsDefined(typeof(AllowPartiallyTrustedCallersAttribute), inherit: false);
2739         }
2740
2741         // Check if the type is allowed to be used in config by checking the APTCA bit
2742         internal static bool IsTypeAllowedInConfig(Type t) {
2743
2744             // Allow everything in full trust
2745             if (HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted))
2746                 return true;
2747
2748             return IsTypeAccessibleFromPartialTrust(t);
2749         }
2750
2751         internal static bool IsTypeAccessibleFromPartialTrust(Type t) {
2752             Assembly assembly = t.Assembly;
2753             
2754             if (assembly.SecurityRuleSet == SecurityRuleSet.Level1) {
2755                 // Level 1 CAS uses transparency as an auditing mechanism rather than an enforcement mechanism, so we can't
2756                 // perform a transparency check. Instead, allow the call to go through if:
2757                 // (a) the referenced assembly is partially trusted, hence it cannot do anything dangerous; or
2758                 // (b) the assembly is fully trusted and has APTCA.
2759                 return (!assembly.IsFullyTrusted || HasAPTCABit(assembly));
2760             }
2761             else {
2762                 // ** TEMPORARY **
2763                 // Some GACed assemblies register critical modules / handlers. We can't break these scenarios for .NET 4.5, but we should
2764                 // remove this APTCA check when we fix DevDiv #85358 and use only the transparency check defined below.
2765                 if (HasAPTCABit(assembly)) {
2766                     return true;
2767                 }
2768                 // ** END TEMPORARY **
2769
2770                 // Level 2 CAS uses transparency as an enforcement mechanism, so we can perform a transparency check.
2771                 // Transparent and SafeCritical types are safe to use from partial trust code.
2772                 return (t.IsSecurityTransparent || t.IsSecuritySafeCritical);
2773             }
2774         }
2775
2776         internal static FileChangesMonitor FileChangesMonitor {
2777             get { return _theRuntime._fcm; }
2778         }
2779
2780         internal static RequestTimeoutManager RequestTimeoutManager {
2781             get { return _theRuntime._timeoutManager; }
2782         }
2783
2784
2785         /// <devdoc>
2786         ///    <para>Provides access to the cache.</para>
2787         /// </devdoc>
2788         public static Cache Cache {
2789             get {
2790
2791                 if (HttpRuntime.AspInstallDirectoryInternal == null) {
2792                     throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2793                 }
2794
2795                 // In a web app, ReadCacheInternalConfig() is called from HttpRuntime.HostingInit.
2796                 // However, if the cache is used by a non-http app, HttpRuntime.HostingInit won't
2797                 // be called and we need to find a way to call ReadCacheInternalConfig().
2798                 // The safe and inexpensive place to call it is when the non-http app accesses the
2799                 // Cache thru HttpRuntime.Cache.
2800                 //
2801                 // ReadCacheInternalConfig() protects itself from being read multiple times.
2802                 //
2803                 Cache cachePublic = _theRuntime._cachePublic;
2804                 if (cachePublic == null) {
2805                     CacheInternal cacheInternal = CacheInternal;
2806                     CacheSection cacheSection = RuntimeConfig.GetAppConfig().Cache;
2807                     cacheInternal.ReadCacheInternalConfig(cacheSection);
2808                     _theRuntime._cachePublic = cacheInternal.CachePublic;
2809                     cachePublic = _theRuntime._cachePublic;
2810                 }
2811
2812                 return cachePublic;
2813             }
2814         }
2815
2816         private void CreateCache() {
2817             lock (this) {
2818                 if (_cacheInternal == null) {
2819                     _cacheInternal = CacheInternal.Create();
2820                 }
2821             }
2822         }
2823
2824         internal static CacheInternal GetCacheInternal(bool createIfDoesNotExist) {
2825             // Note that we only create the cache on first access,
2826             // not in HttpRuntime initialization.
2827             // This prevents cache timers from running when
2828             // the cache is not used.
2829             CacheInternal cacheInternal = _theRuntime._cacheInternal;
2830             if (cacheInternal == null && createIfDoesNotExist) {
2831                 _theRuntime.CreateCache();
2832                 cacheInternal = _theRuntime._cacheInternal;
2833             }
2834
2835             return cacheInternal;
2836         }
2837
2838         internal static CacheInternal CacheInternal {
2839             get { return GetCacheInternal(createIfDoesNotExist: true); }
2840         }
2841
2842         /// <devdoc>
2843         ///    <para>[To be supplied.]</para>
2844         /// </devdoc>
2845         public static string AspInstallDirectory {
2846             get {
2847                 String path = AspInstallDirectoryInternal;
2848
2849                 if (path == null) {
2850                     throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2851                 }
2852
2853                 InternalSecurityPermissions.PathDiscovery(path).Demand();
2854                 return path;
2855             }
2856         }
2857
2858         internal static string AspInstallDirectoryInternal {
2859             get { return s_installDirectory; }
2860         }
2861
2862         //
2863         // Return the client script virtual path, e.g. "/aspnet_client/system_web/2_0_50217"
2864         //
2865         public static string AspClientScriptVirtualPath {
2866             get {
2867                 if (_theRuntime._clientScriptVirtualPath == null) {
2868                     string aspNetVersion = VersionInfo.SystemWebVersion;
2869                     string clientScriptVirtualPath = AspNetClientFilesParentVirtualPath + aspNetVersion.Substring(0, aspNetVersion.LastIndexOf('.')).Replace('.', '_');
2870
2871                     _theRuntime._clientScriptVirtualPath = clientScriptVirtualPath;
2872                 }
2873
2874                 return _theRuntime._clientScriptVirtualPath;
2875             }
2876         }
2877
2878         public static string AspClientScriptPhysicalPath {
2879             get {
2880                 String path = AspClientScriptPhysicalPathInternal;
2881
2882                 if (path == null) {
2883                     throw new HttpException(SR.GetString(SR.Aspnet_not_installed, VersionInfo.SystemWebVersion));
2884                 }
2885
2886                 return path;
2887             }
2888         }
2889
2890         //
2891         // Return the client script physical path, e.g. @"c:\windows\microsoft.net\framework\v2.0.50217.0\asp.netclientfiles"
2892         //
2893         internal static string AspClientScriptPhysicalPathInternal {
2894             get {
2895                 if (_theRuntime._clientScriptPhysicalPath == null) {
2896                     string clientScriptPhysicalPath = System.IO.Path.Combine(AspInstallDirectoryInternal, AspNetClientFilesSubDirectory);
2897
2898                     _theRuntime._clientScriptPhysicalPath = clientScriptPhysicalPath;
2899                 }
2900
2901                 return _theRuntime._clientScriptPhysicalPath;
2902             }
2903         }
2904
2905
2906         /// <devdoc>
2907         ///    <para>[To be supplied.]</para>
2908         /// </devdoc>
2909         public static string ClrInstallDirectory {
2910             get {
2911                 String path = ClrInstallDirectoryInternal;
2912                 InternalSecurityPermissions.PathDiscovery(path).Demand();
2913                 return path;
2914             }
2915         }
2916
2917         internal static string ClrInstallDirectoryInternal {
2918             get { return HttpConfigurationSystem.MsCorLibDirectory; }
2919         }
2920
2921
2922
2923         /// <devdoc>
2924         ///    <para>[To be supplied.]</para>
2925         /// </devdoc>
2926         public static string MachineConfigurationDirectory {
2927             get {
2928                 String path = MachineConfigurationDirectoryInternal;
2929                 InternalSecurityPermissions.PathDiscovery(path).Demand();
2930                 return path;
2931             }
2932         }
2933
2934         internal static string MachineConfigurationDirectoryInternal {
2935             get { return HttpConfigurationSystem.MachineConfigurationDirectory; }
2936         }
2937
2938         internal static bool IsEngineLoaded {
2939             get { return s_isEngineLoaded; }
2940         }
2941
2942
2943         //
2944         //  Static app domain related properties
2945         //
2946
2947
2948         /// <devdoc>
2949         ///    <para>[To be supplied.]</para>
2950         /// </devdoc>
2951         public static String CodegenDir {
2952             get {
2953                 String path = CodegenDirInternal;
2954                 InternalSecurityPermissions.PathDiscovery(path).Demand();
2955                 return path;
2956             }
2957         }
2958
2959         internal static string CodegenDirInternal {
2960             get { return _theRuntime._codegenDir; }
2961         }
2962
2963         internal static string TempDirInternal {
2964             get { return _theRuntime._tempDir; }
2965         }
2966
2967
2968         /// <devdoc>
2969         ///    <para>[To be supplied.]</para>
2970         /// </devdoc>
2971         public static String AppDomainAppId {
2972             get {
2973                 return _theRuntime._appDomainAppId;
2974             }
2975         }
2976
2977         internal static bool IsAspNetAppDomain {
2978             get { return AppDomainAppId != null; }
2979         }
2980
2981
2982
2983         /// <devdoc>
2984         ///    <para>[To be supplied.]</para>
2985         /// </devdoc>
2986         public static String AppDomainAppPath {
2987             get {
2988                 InternalSecurityPermissions.AppPathDiscovery.Demand();
2989                 return AppDomainAppPathInternal;
2990             }
2991         }
2992
2993         internal static string AppDomainAppPathInternal {
2994             get { return _theRuntime._appDomainAppPath; }
2995         }
2996
2997
2998         /// <devdoc>
2999         ///    <para>[To be supplied.]</para>
3000         /// </devdoc>
3001         public static String AppDomainAppVirtualPath {
3002             get {
3003                 return VirtualPath.GetVirtualPathStringNoTrailingSlash(_theRuntime._appDomainAppVPath);
3004             }
3005         }
3006
3007         // Save as AppDomainAppVirtualPath, but includes the trailng slash.  We can't change
3008         // AppDomainAppVirtualPath since it's public.
3009         internal static String AppDomainAppVirtualPathString {
3010             get {
3011                 return VirtualPath.GetVirtualPathString(_theRuntime._appDomainAppVPath);
3012             }
3013         }
3014
3015         internal static VirtualPath AppDomainAppVirtualPathObject {
3016             get {
3017                 return _theRuntime._appDomainAppVPath;
3018             }
3019         }
3020
3021         internal static bool IsPathWithinAppRoot(String path) {
3022             if (AppDomainIdInternal == null)
3023                 return true;    // app domain not initialized
3024
3025             return UrlPath.IsEqualOrSubpath(AppDomainAppVirtualPathString, path);
3026         }
3027
3028
3029         /// <devdoc>
3030         ///    <para>[To be supplied.]</para>
3031         /// </devdoc>
3032         public static String AppDomainId {
3033             [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
3034             get {
3035                 return AppDomainIdInternal;
3036             }
3037         }
3038
3039         internal static string AppDomainIdInternal {
3040             get { return _theRuntime._appDomainId; }
3041         }
3042
3043
3044
3045         /// <devdoc>
3046         ///    <para>[To be supplied.]</para>
3047         /// </devdoc>
3048         public static String BinDirectory {
3049             get {
3050                 String path = BinDirectoryInternal;
3051                 InternalSecurityPermissions.PathDiscovery(path).Demand();
3052                 return path;
3053             }
3054         }
3055
3056         internal static string BinDirectoryInternal {
3057             get { return Path.Combine(_theRuntime._appDomainAppPath, BinDirectoryName) + Path.DirectorySeparatorChar; }
3058
3059         }
3060
3061         internal static VirtualPath CodeDirectoryVirtualPath {
3062             get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(CodeDirectoryName); }
3063         }
3064
3065         internal static VirtualPath ResourcesDirectoryVirtualPath {
3066             get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(ResourcesDirectoryName); }
3067         }
3068
3069         internal static VirtualPath WebRefDirectoryVirtualPath {
3070             get { return _theRuntime._appDomainAppVPath.SimpleCombineWithDir(WebRefDirectoryName); }
3071         }
3072
3073
3074         /// <devdoc>
3075         ///    <para>[To be supplied.]</para>
3076         /// </devdoc>
3077         public static bool IsOnUNCShare {
3078             [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
3079             get {
3080                 return IsOnUNCShareInternal;
3081             }
3082         }
3083
3084         internal static bool IsOnUNCShareInternal {
3085             get { return _theRuntime._isOnUNCShare; }
3086         }
3087
3088
3089         //
3090         //  Static helper to retrieve app domain values
3091         //
3092
3093         private static String GetAppDomainString(String key) {
3094             Object x = Thread.GetDomain().GetData(key);
3095
3096             return x as String;
3097         }
3098
3099         internal static void AddAppDomainTraceMessage(String message) {
3100             const String appDomainTraceKey = "ASP.NET Domain Trace";
3101             AppDomain d = Thread.GetDomain();
3102             String m = d.GetData(appDomainTraceKey) as String;
3103             d.SetData(appDomainTraceKey, (m != null) ? m + " ... " + message : message);
3104         }
3105
3106         // Gets the version of the ASP.NET framework the current web applications is targeting.
3107         // This property is normally set via the <httpRuntime> element's "targetFramework"
3108         // attribute. The property is not guaranteed to return a correct value if the current
3109         // AppDomain is not an ASP.NET web application AppDomain.
3110         public static Version TargetFramework {
3111             get {
3112                 return BinaryCompatibility.Current.TargetFramework;
3113             }
3114         }
3115
3116
3117         //
3118         //  Flags
3119         //
3120
3121         internal static bool DebuggingEnabled {
3122             get { return _theRuntime._debuggingEnabled; }
3123         }
3124
3125         internal static bool ConfigInited {
3126             get { return _theRuntime._configInited; }
3127         }
3128
3129         internal static bool FusionInited {
3130             get { return _theRuntime._fusionInited; }
3131         }
3132
3133         internal static bool ApartmentThreading {
3134             get { return _theRuntime._apartmentThreading; }
3135         }
3136
3137         internal static bool ShutdownInProgress {
3138             get { return _theRuntime._shutdownInProgress; }
3139         }
3140
3141         internal static string TrustLevel {
3142             get { return _theRuntime._trustLevel; }
3143         }
3144
3145         internal static string WpUserId {
3146             get { return _theRuntime._wpUserId; }
3147         }
3148
3149
3150         private void SetTrustLevel(TrustSection trustSection, SecurityPolicySection securityPolicySection) {
3151             // Use a temporary variable, since we use the field as a signal that the trust has really
3152             // been set, which is not the case until later in this method.
3153             string trustLevel = trustSection.Level;
3154
3155             if (trustSection.Level == "Full") {
3156                 _trustLevel = trustLevel;
3157                 return;
3158             }
3159
3160             if (securityPolicySection == null || securityPolicySection.TrustLevels[trustSection.Level] == null) {
3161                 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level), String.Empty, 0);
3162                 //             Do not give out configuration information since we don't know what trust level we are
3163                 //             supposed to be running at.  If the information below is added to the error it might expose
3164                 //             part of the config file that the users does not have permissions to see. VS261145
3165                 //            ,trustSection.ElementInformation.Properties["level"].Source,
3166                 //            trustSection.ElementInformation.Properties["level"].LineNumber);
3167             }
3168             String file = null;
3169             if (trustSection.Level == "Minimal" || trustSection.Level == "Low" ||
3170                 trustSection.Level == "Medium" || trustSection.Level == "High") {
3171                 file = (String)securityPolicySection.TrustLevels[trustSection.Level].LegacyPolicyFileExpanded;
3172             }
3173             else {
3174                 file = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
3175             }
3176             if (file == null || !FileUtil.FileExists(file)) {
3177                 //if HttpContext.Current.IsCustomErrorEnabled
3178                 throw new HttpException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
3179                 //else
3180                 //    throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level),
3181                 //        trustSection.Filename, trustSection.LineNumber);
3182             }
3183
3184             bool foundGacToken = false;
3185 #pragma warning disable 618
3186             PolicyLevel policyLevel = CreatePolicyLevel(file, AppDomainAppPathInternal, CodegenDirInternal, trustSection.OriginUrl, out foundGacToken);
3187
3188             // see if the policy file contained a v1.x UrlMembershipCondition containing
3189             // a GAC token.  If so, let's upgrade it by adding a code group granting
3190             // full trust to code from the GAC
3191             if (foundGacToken) {
3192                 // walk the code groups at the app domain level and look for one that grants
3193                 // access to the GAC with an UrlMembershipCondition.
3194                 CodeGroup rootGroup = policyLevel.RootCodeGroup;
3195                 bool foundGacCondition = false;
3196                 foreach (CodeGroup childGroup in rootGroup.Children) {
3197                     if (childGroup.MembershipCondition is GacMembershipCondition) {
3198                         foundGacCondition = true;
3199
3200                         // if we found the GAC token and also have the GacMembershipCondition
3201                         // the policy file needs to be upgraded to just include the GacMembershipCondition
3202                         Debug.Assert(!foundGacCondition);
3203                         break;
3204                     }
3205                 }
3206
3207                 // add one as a child of the toplevel group after
3208                 // some sanity checking to make sure it's an ASP.NET policy file
3209                 // which always begins with a FirstMatchCodeGroup granting nothing
3210                 // this might not upgrade some custom policy files
3211                 if (!foundGacCondition) {
3212                     if (rootGroup is FirstMatchCodeGroup) {
3213                         FirstMatchCodeGroup firstMatch = (FirstMatchCodeGroup)rootGroup;
3214                         if (firstMatch.MembershipCondition is AllMembershipCondition &&
3215                            firstMatch.PermissionSetName == "Nothing") {
3216                             PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
3217
3218                             CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(),
3219                                                                     new PolicyStatement(fullTrust));
3220
3221
3222                             // now, walk the current groups and insert our new group
3223                             // immediately before the old Gac group
3224                             // we'll need to use heuristics for this:
3225                             // it will be an UrlMembershipCondition group with full trust
3226                             CodeGroup newRoot = new FirstMatchCodeGroup(rootGroup.MembershipCondition, rootGroup.PolicyStatement);
3227                             foreach (CodeGroup childGroup in rootGroup.Children) {
3228
3229                                 // is this the target old $Gac$ group?
3230                                 // insert our new GacMembershipCondition group ahead of it
3231                                 if ((childGroup is UnionCodeGroup) &&
3232                                    (childGroup.MembershipCondition is UrlMembershipCondition) &&
3233                                    childGroup.PolicyStatement.PermissionSet.IsUnrestricted()) {
3234                                     if (null != gacGroup) {
3235                                         newRoot.AddChild(gacGroup);
3236                                         gacGroup = null;
3237                                     }
3238                                 }
3239
3240                                 // append this group to the root group
3241                                 // AddChild itself does a deep Copy to get any
3242                                 // child groups so we don't need one here
3243                                 newRoot.AddChild(childGroup);
3244                             }
3245
3246                             policyLevel.RootCodeGroup = newRoot;
3247                             //Debug.Trace("internal", "PolicyLevel: " + policyLevel.ToXml());
3248                         }
3249                     }
3250                 }
3251 #pragma warning restore 618
3252             }
3253
3254
3255 #pragma warning disable 618
3256             AppDomain.CurrentDomain.SetAppDomainPolicy(policyLevel);
3257             _namedPermissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
3258 #pragma warning restore 618
3259
3260             _trustLevel = trustLevel;
3261
3262             _fcm.StartMonitoringFile(file, new FileChangeEventHandler(this.OnSecurityPolicyFileChange));
3263         }
3264
3265 #pragma warning disable 618
3266         private static PolicyLevel CreatePolicyLevel(String configFile, String appDir, String binDir, String strOriginUrl, out bool foundGacToken) {
3267             // Read in the config file to a string.
3268             FileStream file = new FileStream(configFile, FileMode.Open, FileAccess.Read);
3269             StreamReader reader = new StreamReader(file, Encoding.UTF8);
3270             String strFileData = reader.ReadToEnd();
3271
3272             reader.Close();
3273
3274             appDir = FileUtil.RemoveTrailingDirectoryBackSlash(appDir);
3275             binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir);
3276
3277             strFileData = strFileData.Replace("$AppDir$", appDir);
3278             strFileData = strFileData.Replace("$AppDirUrl$", MakeFileUrl(appDir));
3279             strFileData = strFileData.Replace("$CodeGen$", MakeFileUrl(binDir));
3280             if (strOriginUrl == null)
3281                 strOriginUrl = String.Empty;
3282             strFileData = strFileData.Replace("$OriginHost$", strOriginUrl);
3283
3284             // see if the file contains a GAC token
3285             // if so, do the replacement and record the
3286             // fact so that we later add a GacMembershipCondition
3287             // codegroup to the PolicyLevel
3288             int ndx = strFileData.IndexOf("$Gac$", StringComparison.Ordinal);
3289             if (ndx != -1) {
3290                 string gacLocation = GetGacLocation();
3291                 if (gacLocation != null)
3292                     gacLocation = MakeFileUrl(gacLocation);
3293                 if (gacLocation == null)
3294                     gacLocation = String.Empty;
3295
3296                 strFileData = strFileData.Replace("$Gac$", gacLocation);
3297                 foundGacToken = true;
3298             }
3299             else {
3300                 foundGacToken = false;
3301             }
3302
3303             return SecurityManager.LoadPolicyLevelFromString(strFileData, PolicyLevelType.AppDomain);
3304         }
3305 #pragma warning restore 618
3306
3307         private void SetTrustParameters(TrustSection trustSection, SecurityPolicySection securityPolicySection, PolicyLevel policyLevel) {
3308             _trustLevel = trustSection.Level;
3309             if (_trustLevel != "Full") {
3310                 // if we are in partial trust, HostingEnvironment should init HttpRuntime with a non-null PolicyLevel object
3311                 Debug.Assert(policyLevel != null);
3312
3313                 _namedPermissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
3314                 _policyLevel = policyLevel;
3315                 _hostSecurityPolicyResolverType = trustSection.HostSecurityPolicyResolverType;
3316                 String file = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
3317                 _fcm.StartMonitoringFile(file, new FileChangeEventHandler(this.OnSecurityPolicyFileChange));
3318             }
3319         }
3320
3321         /*
3322          * Notification when something in the code-access security policy file changed
3323          */
3324         private void OnSecurityPolicyFileChange(Object sender, FileChangeEvent e) {
3325             // shutdown the app domain
3326             Debug.Trace("AppDomainFactory", "Shutting down appdomain because code-access security policy file changed");
3327             string message = FileChangesMonitor.GenerateErrorMessage(e.Action, e.FileName);
3328             if (message == null) {
3329                 message = "Change in code-access security policy file";
3330             }
3331             ShutdownAppDomain(ApplicationShutdownReason.ChangeInSecurityPolicyFile,
3332                               message);
3333         }
3334
3335
3336         // notification when app_offline.htm file changed or created
3337         private void OnAppOfflineFileChange(Object sender, FileChangeEvent e) {
3338             // shutdown the app domain
3339             Debug.Trace("AppOffline", AppOfflineFileName + " changed - shutting down the app domain");
3340             Debug.Trace("AppDomainFactory", "Shutting down appdomain because " + AppOfflineFileName + " file changed");
3341             // WOS 1948399: set _userForcedShutdown to avoid DelayNotificationTimeout, since first request has not completed yet in integrated mode;
3342             SetUserForcedShutdown();
3343             string message = FileChangesMonitor.GenerateErrorMessage(e.Action, AppOfflineFileName);
3344             if (message == null) {
3345                 message = "Change in " + AppOfflineFileName;
3346             }
3347             ShutdownAppDomain(ApplicationShutdownReason.ConfigurationChange, message);
3348         }
3349
3350         internal static String MakeFileUrl(String path) {
3351             Uri uri = new Uri(path);
3352             return uri.ToString();
3353         }
3354
3355         internal static String GetGacLocation() {
3356
3357             StringBuilder buf = new StringBuilder(262);
3358             int iSize = 260;
3359
3360             // 
3361
3362             if (UnsafeNativeMethods.GetCachePath(2, buf, ref iSize) >= 0)
3363                 return buf.ToString();
3364             throw new HttpException(SR.GetString(SR.GetGacLocaltion_failed));
3365         }
3366
3367
3368         /*
3369          * Remove from metabase all read/write/browse permission from certain subdirs
3370          *
3371          */
3372         internal static void RestrictIISFolders(HttpContext context) {
3373             int ret;
3374
3375             HttpWorkerRequest wr = context.WorkerRequest;
3376
3377             Debug.Assert(AppDomainAppId != null);
3378
3379             // Don't do it if we are not running on IIS
3380             if (wr == null || !(wr is System.Web.Hosting.ISAPIWorkerRequest)) {
3381                 return;
3382             }
3383
3384             // Do it only for IIS 5
3385 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
3386             if (!(wr is System.Web.Hosting.ISAPIWorkerRequestInProcForIIS6))
3387 #endif // !FEATURE_PAL
3388  {
3389                 byte[] bufin;
3390                 byte[] bufout = new byte[1];   // Just to keep EcbCallISAPI happy
3391
3392                 bufin = BitConverter.GetBytes(UnsafeNativeMethods.RESTRICT_BIN);
3393                 ret = context.CallISAPI(UnsafeNativeMethods.CallISAPIFunc.RestrictIISFolders, bufin, bufout);
3394                 if (ret != 1) {
3395                     // Cannot pass back any HR from inetinfo.exe because CSyncPipeManager::GetDataFromIIS
3396                     // does not support passing back any value when there is an error.
3397                     Debug.Trace("RestrictIISFolders", "Cannot restrict folder access for '" + AppDomainAppId + "'.");
3398                 }
3399             }
3400         }
3401
3402         //
3403         // Helper to create instances (public vs. internal/private ctors, see 89781)
3404         //
3405
3406         internal static Object CreateNonPublicInstance(Type type) {
3407             return CreateNonPublicInstance(type, null);
3408         }
3409
3410         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
3411         internal static Object CreateNonPublicInstance(Type type, Object[] args) {
3412             return Activator.CreateInstance(
3413                 type,
3414                 BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
3415                 null,
3416                 args,
3417                 null);
3418         }
3419
3420         internal static Object CreatePublicInstance(Type type) {
3421             return Activator.CreateInstance(type);
3422         }
3423
3424 #if !DONTUSEFACTORYGENERATOR
3425         // Cache instances of IWebObjectFactory for each Type, which allow us
3426         // to instantiate the objects very efficiently, compared to calling
3427         // Activator.CreateInstance on every call.
3428         private static FactoryGenerator s_factoryGenerator;
3429         private static Hashtable s_factoryCache;
3430         private static bool s_initializedFactory;
3431         private static object s_factoryLock = new Object();
3432
3433 #endif // DONTUSEFACTORYGENERATOR
3434
3435         /*
3436          * Faster implementation of CreatePublicInstance.  It generates bits of IL
3437          * on the fly to achieve the improve performance.  this should only be used
3438          * in cases where the number of different types to be created is well bounded.
3439          * Otherwise, we would create too much IL, which can bloat the process.
3440          */
3441         internal static Object FastCreatePublicInstance(Type type) {
3442
3443 #if DONTUSEFACTORYGENERATOR
3444             return CreatePublicInstance(type);
3445 #else
3446
3447             // Only use the factory logic if the assembly is in the GAC, to avoid getting
3448             // assembly conflicts (VSWhidbey 405086)
3449             if (!type.Assembly.GlobalAssemblyCache) {
3450                 return CreatePublicInstance(type);
3451             }
3452
3453             // Create the factory generator on demand
3454             if (!s_initializedFactory) {
3455
3456                 // Devdiv 90810 - Synchronize to avoid race condition
3457                 lock (s_factoryLock) {
3458                     if (!s_initializedFactory) {
3459                         s_factoryGenerator = new FactoryGenerator();
3460
3461                         // Create the factory cache
3462                         s_factoryCache = Hashtable.Synchronized(new Hashtable());
3463
3464                         s_initializedFactory = true;
3465                     }
3466                 }
3467             }
3468
3469             // First, check if it's cached
3470             IWebObjectFactory factory = (IWebObjectFactory)s_factoryCache[type];
3471
3472             if (factory == null) {
3473
3474                 Debug.Trace("FastCreatePublicInstance", "Creating generator for type " + type.FullName);
3475
3476                 // Create the object factory
3477                 factory = s_factoryGenerator.CreateFactory(type);
3478
3479                 // Cache the factory
3480                 s_factoryCache[type] = factory;
3481             }
3482
3483             return factory.CreateInstance();
3484 #endif // DONTUSEFACTORYGENERATOR
3485         }
3486
3487         internal static Object CreatePublicInstance(Type type, Object[] args) {
3488             if (args == null)
3489                 return Activator.CreateInstance(type);
3490
3491             return Activator.CreateInstance(type, args);
3492         }
3493
3494         static string GetCurrentUserName() {
3495             try {
3496                 return WindowsIdentity.GetCurrent().Name;
3497             }
3498             catch {
3499                 return null;
3500             }
3501         }
3502
3503         void RaiseShutdownWebEventOnce() {
3504             if (!_shutdownWebEventRaised) {
3505                 lock (this) {
3506                     if (!_shutdownWebEventRaised) {
3507                         // Raise Web Event
3508                         WebBaseEvent.RaiseSystemEvent(this, WebEventCodes.ApplicationShutdown,
3509                                 WebApplicationLifetimeEvent.DetailCodeFromShutdownReason(ShutdownReason));
3510
3511                         _shutdownWebEventRaised = true;
3512                     }
3513                 }
3514             }
3515         }
3516
3517         private static string _DefaultPhysicalPathOnMapPathFailure;
3518         private void RelaxMapPathIfRequired() {
3519             try {
3520                 RuntimeConfig config = RuntimeConfig.GetAppConfig();
3521                 if (config != null && config.HttpRuntime != null && config.HttpRuntime.RelaxedUrlToFileSystemMapping) {
3522                     _DefaultPhysicalPathOnMapPathFailure = Path.Combine(_appDomainAppPath, "NOT_A_VALID_FILESYSTEM_PATH");
3523                 }
3524             } catch {}
3525         }
3526         internal static bool IsMapPathRelaxed {
3527             get {
3528                 return _DefaultPhysicalPathOnMapPathFailure != null;
3529             }
3530         }
3531         internal static string GetRelaxedMapPathResult(string originalResult) {
3532             if (!IsMapPathRelaxed) // Feature not enabled?
3533                 return originalResult;
3534
3535             if (originalResult == null) // null is never valid: Return the hard coded default physical path
3536                 return _DefaultPhysicalPathOnMapPathFailure;
3537
3538             // Does it contain an invalid file-path char?
3539             if (originalResult.IndexOfAny(s_InvalidPhysicalPathChars) >= 0)
3540                 return _DefaultPhysicalPathOnMapPathFailure;
3541
3542             // Final check: do the full check to ensure it is valid
3543             try {
3544                 bool pathTooLong;
3545                 if (FileUtil.IsSuspiciousPhysicalPath(originalResult, out pathTooLong) || pathTooLong)
3546                     return _DefaultPhysicalPathOnMapPathFailure;
3547             } catch {
3548                 return _DefaultPhysicalPathOnMapPathFailure;
3549             }
3550
3551             // it is valid
3552             return originalResult;
3553         }
3554     }
3555
3556
3557     public enum ApplicationShutdownReason {
3558
3559         None = 0,
3560
3561         HostingEnvironment = 1,
3562
3563         ChangeInGlobalAsax = 2,
3564
3565         ConfigurationChange = 3,
3566
3567         UnloadAppDomainCalled = 4,
3568
3569         ChangeInSecurityPolicyFile = 5,
3570
3571         BinDirChangeOrDirectoryRename = 6,
3572
3573         BrowsersDirChangeOrDirectoryRename = 7,
3574
3575         CodeDirChangeOrDirectoryRename = 8,
3576
3577         ResourcesDirChangeOrDirectoryRename = 9,
3578
3579         IdleTimeout = 10,
3580
3581         PhysicalApplicationPathChanged = 11,
3582
3583         HttpRuntimeClose = 12,
3584
3585         InitializationError = 13,
3586
3587         MaxRecompilationsReached = 14,
3588
3589         BuildManagerChange = 15,
3590     };
3591
3592
3593 }