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