Moving BSTR conv to native code in SecureStringToBSTR.
[mono.git] / mcs / class / referencesource / System.Web / Hosting / ApplicationManager.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="ApplicationManager.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7
8 namespace System.Web.Hosting {
9     using System;
10     using System.Collections;
11     using System.Collections.Generic;
12     using System.Configuration;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Globalization;
15     using System.IO;
16     using System.Linq;
17     using System.Reflection;
18     using System.Runtime.ExceptionServices;
19     using System.Runtime.InteropServices;
20     using System.Runtime.Remoting;
21     using System.Runtime.Versioning;
22     using System.Security;
23     using System.Security.Permissions;
24     using System.Security.Policy;
25     using System.Text;
26     using System.Threading;
27     using System.Threading.Tasks;
28     using System.Web;
29     using System.Web.Compilation;
30     using System.Web.Configuration;
31     using System.Web.Util;
32
33     public enum HostSecurityPolicyResults {
34         DefaultPolicy = 0,
35         FullTrust = 1,
36         AppDomainTrust = 2,
37         Nothing = 3
38     };
39
40     [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
41     public class HostSecurityPolicyResolver {
42         public virtual HostSecurityPolicyResults ResolvePolicy(Evidence evidence) {
43             return HostSecurityPolicyResults.DefaultPolicy;
44         }
45     }
46
47
48
49     internal class LockableAppDomainContext {
50         internal HostingEnvironment HostEnv { get; set; }
51         internal string PreloadContext { get; set; }
52         internal bool RetryingPreload { get; set; }
53
54         internal LockableAppDomainContext() {
55         }
56     }
57
58     public sealed class ApplicationManager : MarshalByRefObject {
59
60         private const string _clrQuirkAppSettingsAppContextPrefix = "AppContext.SetSwitch:";
61         private const string _regexMatchTimeoutKey = "REGEX_DEFAULT_MATCH_TIMEOUT";
62         private static readonly StrongName _mwiV1StrongName = GetMicrosoftWebInfrastructureV1StrongName();
63
64         private static Object _applicationManagerStaticLock = new Object();
65
66         // open count (when last close goes to 0 it shuts down everything)
67         int _openCount = 0;
68         bool _shutdownInProgress = false;
69
70         // table of app domains (LockableAppDomainContext objects) by app id
71         // To simplify per-appdomain synchronization we will never remove LockableAppDomainContext objects from this table even when the AD is unloaded
72         // We may need to fix it if profiling shows a noticeable impact on performance
73         private Dictionary <string, LockableAppDomainContext> _appDomains = new Dictionary<string, LockableAppDomainContext>(StringComparer.OrdinalIgnoreCase);
74         // count of HostingEnvironment instances that is referenced in _appDomains collection
75         private int _accessibleHostingEnvCount;
76
77         // could differ from _appDomains or _accessibleHostingEnvCount count (host env is active some time after it is removed)
78         private int _activeHostingEnvCount;
79
80         // pending callback to respond to ping (typed as Object to do Interlocked operations)
81         private Object _pendingPingCallback;
82         // delegate OnRespondToPing
83         private WaitCallback _onRespondToPingWaitCallback;
84
85         // single instance of app manager
86         private static ApplicationManager _theAppManager;
87
88         // single instance of cache manager
89         private static CacheManager _cm;
90
91         // store fatal exception to assist debugging
92         private static Exception _fatalException = null;
93
94         internal ApplicationManager() {
95             _onRespondToPingWaitCallback = new WaitCallback(this.OnRespondToPingWaitCallback);
96
97             // VSWhidbey 555767: Need better logging for unhandled exceptions (http://support.microsoft.com/?id=911816)
98             // We only add a handler in the default domain because it will be notified when an unhandled exception 
99             // occurs in ANY domain.  
100             // WOS 1983175: (weird) only the handler in the default domain is notified when there is an AV in a native module
101             // while we're in a call to MgdIndicateCompletion.
102             AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
103         }
104
105         private void InitCacheManager(long privateBytesLimit) {
106             if (_cm == null) {
107                 lock (_applicationManagerStaticLock) {
108                     if (_cm == null && !_shutdownInProgress) {
109                         _cm = new CacheManager(this, privateBytesLimit);
110                     }
111                 }
112             }
113         }
114
115         private void DisposeCacheManager() {
116             if (_cm != null) {
117                 lock (_applicationManagerStaticLock) {
118                     if (_cm != null) {
119                         _cm.Dispose();
120                         _cm = null;
121                     }
122                 }
123             }
124         }
125
126         // Each cache must update the total with the difference between it's current size and it's previous size.
127         // To reduce cross-domain costs, this also returns the updated total size.
128         internal long GetUpdatedTotalCacheSize(long sizeUpdate) {
129             CacheManager cm = _cm;
130             return (cm != null) ? cm.GetUpdatedTotalCacheSize(sizeUpdate) : 0;
131         }
132
133         internal long TrimCaches(int percent) {
134             long trimmedOrExpired = 0;
135             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
136             foreach (LockableAppDomainContext ac in apps.Values) {
137                 lock (ac) {
138                     HostingEnvironment env = ac.HostEnv;
139                     if (_shutdownInProgress) {
140                         break;
141                     }
142                     if (env == null) {
143                         continue;
144                     }
145                     trimmedOrExpired += env.TrimCache(percent);
146                 }
147             }
148             return trimmedOrExpired;
149         }
150
151         internal bool ShutdownInProgress {
152             get {
153                 return _shutdownInProgress;
154             }
155         }
156
157         internal static void RecordFatalException(Exception e) {
158             RecordFatalException(AppDomain.CurrentDomain, e);
159         }
160
161         internal static void RecordFatalException(AppDomain appDomain, Exception e) {
162             // store the exception from the first caller to assist debugging
163             object originalValue = Interlocked.CompareExchange(ref _fatalException, e, null);
164
165             if (originalValue == null) {
166                 // create event log entry
167                 Misc.WriteUnhandledExceptionToEventLog(appDomain, e);
168             }
169         }
170
171         private static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) {
172             // if the CLR is not terminating, ignore the notification
173             if (!eventArgs.IsTerminating) {
174                 return;
175             }
176
177             Exception exception = eventArgs.ExceptionObject as Exception;
178             if (exception == null) {
179                 return;
180             }
181
182             AppDomain appDomain = sender as AppDomain;
183             if (appDomain == null) {
184                 return;
185             }
186
187             RecordFatalException(appDomain, exception);
188         }
189
190         public override Object InitializeLifetimeService() {
191             return null; // never expire lease
192         }
193
194         //
195         // public ApplicationManager methods
196         //
197
198
199         public static ApplicationManager GetApplicationManager() {
200             if (_theAppManager == null) {
201                 lock (_applicationManagerStaticLock) {
202                     if (_theAppManager == null) {
203                         if (HostingEnvironment.IsHosted)
204                             _theAppManager = HostingEnvironment.GetApplicationManager();
205
206                         if (_theAppManager == null)
207                             _theAppManager = new ApplicationManager();
208                     }
209                 }
210             }
211
212             return _theAppManager;
213         }
214
215
216         [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
217         public void Open() {
218             Interlocked.Increment(ref _openCount);
219         }
220
221
222         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
223         public void Close() {
224             if (Interlocked.Decrement(ref _openCount) > 0)
225                 return;
226
227             // need to shutdown everything
228             ShutdownAll();
229         }
230
231         private string CreateSimpleAppID(VirtualPath virtualPath, string physicalPath, string siteName) {
232             // Put together some unique app id
233             string appId = String.Concat(virtualPath.VirtualPathString, physicalPath);
234
235             if (!String.IsNullOrEmpty(siteName)) {
236                 appId = String.Concat(appId, siteName);
237             }
238
239             return appId.GetHashCode().ToString("x", CultureInfo.InvariantCulture);
240         }
241
242         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
243         public IRegisteredObject CreateObject(IApplicationHost appHost, Type type) {
244             if (appHost == null) {
245                 throw new ArgumentNullException("appHost");
246             }
247             if (type == null) {
248                 throw new ArgumentNullException("type");
249             }
250
251             string appID = CreateSimpleAppID(appHost);
252             return CreateObjectInternal(appID, type, appHost, false);            
253         }
254
255         [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
256         public IRegisteredObject CreateObject(String appId, Type type, string virtualPath, string physicalPath, bool failIfExists) {
257             return CreateObject(appId, type, virtualPath, physicalPath, failIfExists, false /*throwOnError*/);
258         }
259
260         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
261         public IRegisteredObject CreateObject(String appId, Type type, string virtualPath, string physicalPath,
262                                               bool failIfExists, bool throwOnError) {
263             // check args
264             if (appId == null)
265                 throw new ArgumentNullException("appId");
266
267             SimpleApplicationHost appHost = new SimpleApplicationHost(VirtualPath.CreateAbsolute(virtualPath), physicalPath);
268
269             // if throw on error flag is set, create hosting parameters accordingly
270             HostingEnvironmentParameters hostingParameters = null;
271
272             if (throwOnError) {
273                 hostingParameters = new HostingEnvironmentParameters();
274                 hostingParameters.HostingFlags = HostingEnvironmentFlags.ThrowHostingInitErrors;
275
276             }
277
278             // call the internal method
279             return CreateObjectInternal(appId, type, appHost, failIfExists, hostingParameters);
280         }
281
282         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
283         internal IRegisteredObject CreateObjectInternal(String appId, Type type, IApplicationHost appHost, bool failIfExists) {
284             // check args
285             if (appId == null)
286                 throw new ArgumentNullException("appId");
287
288             if (type == null)
289                 throw new ArgumentNullException("type");
290
291             if (appHost == null)
292                 throw new ArgumentNullException("appHost");
293
294             // call the internal method
295             return CreateObjectInternal(appId, type, appHost, failIfExists, null /*hostingParameters*/);
296         }
297
298         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
299         internal IRegisteredObject CreateObjectInternal(
300                                         String appId,
301                                         Type type,
302                                         IApplicationHost appHost,
303                                         bool failIfExists,
304                                         HostingEnvironmentParameters hostingParameters) {
305
306             // check that type is as IRegisteredObject
307             if (!typeof(IRegisteredObject).IsAssignableFrom(type))
308                 throw new ArgumentException(SR.GetString(SR.Not_IRegisteredObject, type.FullName), "type");
309
310             // get hosting environment
311             HostingEnvironment env = GetAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
312
313             // create the managed object in the worker app domain
314             // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
315             // always the case, so we marshal the assembly qualified name instead
316             ObjectHandle h = env.CreateWellKnownObjectInstance(type.AssemblyQualifiedName, failIfExists);
317             return (h != null) ? h.Unwrap() as IRegisteredObject : null;
318         }
319
320         internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
321                                         String physicalPath,
322                                         string virtualPath,
323                                         Type type,
324                                         out String appId,
325                                         out IApplicationHost appHost) {
326             return CreateObjectWithDefaultAppHostAndAppId(physicalPath,
327                 VirtualPath.CreateNonRelative(virtualPath), type, out appId, out appHost);
328         }
329
330         internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
331                                         String physicalPath,
332                                         VirtualPath virtualPath,
333                                         Type type,
334                                         out String appId,
335                                         out IApplicationHost appHost) {
336
337             HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
338             hostingParameters.HostingFlags = HostingEnvironmentFlags.DontCallAppInitialize;
339
340             return CreateObjectWithDefaultAppHostAndAppId(
341                         physicalPath,
342                         virtualPath,
343                         type,
344                         false,
345                         hostingParameters,
346                         out appId,
347                         out appHost);
348         }
349
350         internal IRegisteredObject CreateObjectWithDefaultAppHostAndAppId(
351                                         String physicalPath,
352                                         VirtualPath virtualPath,
353                                         Type type,
354                                         bool failIfExists,
355                                         HostingEnvironmentParameters hostingParameters,
356                                         out String appId,
357                                         out IApplicationHost appHost) {
358
359 #if !FEATURE_PAL // FEATURE_PAL does not enable IIS-based hosting features
360             if (physicalPath == null) { 
361
362                 // If the physical path is null, we use an ISAPIApplicationHost based
363                 // on the virtual path (or metabase id).
364
365                 // Make sure the static HttpRuntime is created so isapi assembly can be loaded properly.
366                 HttpRuntime.ForceStaticInit();
367
368                 ISAPIApplicationHost isapiAppHost = new ISAPIApplicationHost(virtualPath.VirtualPathString, null, true, null, hostingParameters.IISExpressVersion);
369
370                 appHost = isapiAppHost;
371                 appId = isapiAppHost.AppId;
372                 virtualPath = VirtualPath.Create(appHost.GetVirtualPath());
373                 physicalPath = FileUtil.FixUpPhysicalDirectory(appHost.GetPhysicalPath());
374             }
375             else {
376 #endif // !FEATURE_PAL
377                 // If the physical path was passed in, don't use an Isapi host. Instead,
378                 // use a simple app host which does simple virtual to physical mappings
379
380                 // Put together some unique app id
381                 appId = CreateSimpleAppID(virtualPath, physicalPath, null);
382
383                 appHost = new SimpleApplicationHost(virtualPath, physicalPath);
384             }
385
386             string precompTargetPhysicalDir = hostingParameters.PrecompilationTargetPhysicalDirectory;
387             if (precompTargetPhysicalDir != null) {
388                 // Change the appID so we use a different codegendir in precompile for deployment scenario,
389                 // this ensures we don't use or pollute the regular codegen files.  Also, use different
390                 // ID's depending on whether the precompilation is Updatable (VSWhidbey 383239)
391                 if ((hostingParameters.ClientBuildManagerParameter != null) && 
392                     (hostingParameters.ClientBuildManagerParameter.PrecompilationFlags & PrecompilationFlags.Updatable) == 0)
393                     appId = appId + "_precompile";
394                 else
395                     appId = appId + "_precompile_u";
396             }
397
398             return CreateObjectInternal(appId, type, appHost, failIfExists, hostingParameters);
399         }
400
401
402         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
403         public IRegisteredObject GetObject(String appId, Type type) {
404             // check args
405             if (appId == null)
406                 throw new ArgumentNullException("appId");
407             if (type == null)
408                 throw new ArgumentNullException("type");
409
410             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
411             lock (ac) {
412                 HostingEnvironment env = ac.HostEnv;
413                 if (env == null)
414                     return null;
415
416                 // find the instance by type
417                 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
418                 // always the case, so we marshal the assembly qualified name instead
419                 ObjectHandle h = env.FindWellKnownObject(type.AssemblyQualifiedName);
420                 return (h != null) ? h.Unwrap() as IRegisteredObject : null;
421             }
422         }
423
424         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
425         public AppDomain GetAppDomain(string appId) {
426             if (appId == null) {
427                 throw new ArgumentNullException("appId");
428             }
429
430             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
431             lock (ac) {
432                 HostingEnvironment env = ac.HostEnv;
433                 if (env == null) {
434                     return null;
435                 }
436
437                 return env.HostedAppDomain;
438             }
439         }
440
441         public AppDomain GetAppDomain(IApplicationHost appHost) {
442             if (appHost == null) {
443                 throw new ArgumentNullException("appHost");
444             }
445             string appID = CreateSimpleAppID(appHost);
446             return GetAppDomain(appID);
447         }
448
449         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This isn't a dangerous method.")]
450         private string CreateSimpleAppID(IApplicationHost appHost) {
451             if (appHost == null) {
452                 throw new ArgumentNullException("appHost");
453             }
454             return CreateSimpleAppID(VirtualPath.Create(appHost.GetVirtualPath()),
455                                      appHost.GetPhysicalPath(), appHost.GetSiteName());
456         }
457         
458
459         // if a "well-known" object of the specified type already exists in the application,
460         // remove the app from the managed application table.  This is
461         // used in IIS7 integrated mode when IIS7 determines that it is necessary to create
462         // a new application and shutdown the old one.
463         internal void RemoveFromTableIfRuntimeExists(String appId, Type runtimeType) {
464             // check args
465             if (appId == null)
466                 throw new ArgumentNullException("appId");
467             if (runtimeType == null)
468                 throw new ArgumentNullException("runtimeType");
469
470             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
471             lock (ac) {
472                 // get hosting environment
473                 HostingEnvironment env = ac.HostEnv;
474                 if (env == null)
475                     return;
476
477                 // find the instance by type
478                 // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
479                 // always the case, so we marshal the assembly qualified name instead
480                 ObjectHandle h = env.FindWellKnownObject(runtimeType.AssemblyQualifiedName);
481                 if (h != null)
482                 {
483                     // ensure that it is removed from _appDomains by calling
484                     // HostingEnvironmentShutdownInitiated directly.
485                     HostingEnvironmentShutdownInitiated(appId, env);
486                 }
487             }
488         }
489
490         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
491         public void StopObject(String appId, Type type) {
492             // check args
493             if (appId == null)
494                 throw new ArgumentNullException("appId");
495             if (type == null)
496                 throw new ArgumentNullException("type");
497
498             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
499             lock (ac) {
500                 HostingEnvironment env = ac.HostEnv;
501                 if (env != null) {
502                     // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
503                     // always the case, so we marshal the assembly qualified name instead
504                     env.StopWellKnownObject(type.AssemblyQualifiedName);
505                 }
506             }
507         }
508
509
510         public bool IsIdle() {
511             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
512
513             foreach (LockableAppDomainContext ac in apps.Values) {
514                 lock (ac) {
515                     HostingEnvironment env = ac.HostEnv;
516                     bool idle = (null == env) ? true : env.IsIdle();
517
518                     if (!idle)
519                         return false;
520                 }
521             }
522
523             return true;
524         }
525
526
527         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
528         public void ShutdownApplication(String appId) {
529             if (appId == null)
530                 throw new ArgumentNullException("appId");
531
532             LockableAppDomainContext ac = GetLockableAppDomainContext(appId);
533             lock (ac) {
534                 if (ac.HostEnv != null) {
535                     ac.HostEnv.InitiateShutdownInternal();
536                 }
537             }
538         }
539
540
541         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
542         public void ShutdownAll() {
543             _shutdownInProgress = true;
544             Dictionary <string, LockableAppDomainContext> oldTable = null;
545
546             DisposeCacheManager();
547
548             lock (this) {
549                 oldTable = _appDomains;
550                 // don't keep references to hosting environments anymore
551                 _appDomains = new Dictionary<string, LockableAppDomainContext>(StringComparer.OrdinalIgnoreCase);
552             }
553
554
555             foreach (KeyValuePair <string, LockableAppDomainContext> p in oldTable) {
556                 LockableAppDomainContext ac = p.Value;
557                 lock (ac) {
558                     HostingEnvironment env = ac.HostEnv;
559                     if (null != env) {
560                         env.InitiateShutdownInternal();
561                     }
562                 }
563             }
564         
565             for (int iter=0; _activeHostingEnvCount > 0 && iter < 3000; iter++) // Wait at most 5 minutes
566                 Thread.Sleep(100);
567         }
568
569
570         [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
571         public ApplicationInfo[] GetRunningApplications() {
572             ArrayList appList = new ArrayList();
573
574             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
575
576             foreach (LockableAppDomainContext ac in apps.Values) {
577                 lock (ac) {
578                     HostingEnvironment env = ac.HostEnv;
579                     if (env != null) {
580                         appList.Add(env.GetApplicationInfo());
581                     }
582                 }
583             }
584
585             int n = appList.Count;
586             ApplicationInfo[] result = new ApplicationInfo[n];
587
588             if (n > 0) {
589                 appList.CopyTo(result);
590             }
591
592             return result;
593         }
594
595         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This method fails due to serialization issues if not called by ASP.NET.")]
596         internal AppDomainInfo [] GetAppDomainInfos()
597         {
598             ArrayList appList = new ArrayList();
599             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
600
601             foreach (LockableAppDomainContext ac in apps.Values) {
602                 lock (ac) {
603                     HostingEnvironment hostEnv = ac.HostEnv;
604                     if (hostEnv == null) {
605                         continue;
606                     }
607
608                     IApplicationHost appHost = hostEnv.InternalApplicationHost;
609                     ApplicationInfo appInfo = hostEnv.GetApplicationInfo();
610                     int siteId = 0;
611
612                     if (appHost != null) {
613                         try {
614                             siteId = Int32.Parse(appHost.GetSiteID(), CultureInfo.InvariantCulture);
615                         }
616                         catch {
617                         }
618                     }
619
620                     AppDomainInfo appDomainInfo = new AppDomainInfo(appInfo.ID,
621                                                       appInfo.VirtualPath,
622                                                       appInfo.PhysicalPath,
623                                                       siteId,
624                                                       hostEnv.GetIdleValue());
625
626                     appList.Add(appDomainInfo);
627                 }
628             }
629
630             return (AppDomainInfo[]) appList.ToArray(typeof(AppDomainInfo));
631         }
632
633         //
634         // APIs for the process host to suspend / resume all running applications
635         //
636
637         [SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Justification = "'this' is never a MBRO proxy object.")]
638         internal object SuspendAllApplications() {
639             LockableAppDomainContext[] allAppDomainContexts;
640
641             lock (this) {
642                 allAppDomainContexts = _appDomains.Values.ToArray();
643             }
644
645             ApplicationResumeStateContainer[] resumeContainers = Task.WhenAll(allAppDomainContexts.Select(CreateSuspendTask)).Result;
646             return resumeContainers;
647         }
648
649         private static Task<ApplicationResumeStateContainer> _dummyCompletedSuspendTask = Task.FromResult<ApplicationResumeStateContainer>(null);
650         private static Task<ApplicationResumeStateContainer> CreateSuspendTask(LockableAppDomainContext appDomainContext) {
651             // dictionary contained a null entry?
652             if (appDomainContext == null) {
653                 return _dummyCompletedSuspendTask;
654             }
655
656             HostingEnvironment hostEnv;
657             lock (appDomainContext) {
658                 hostEnv = appDomainContext.HostEnv;
659             }
660
661             // Quick check: is this a dummy context that had no associated application?
662             if (hostEnv == null) {
663                 return _dummyCompletedSuspendTask;
664             }
665
666             // QUWI since we want to run each application's suspend method in parallel.
667             // Unsafe since we don't care about impersonation, identity, etc.
668             // Don't use Task.Run since it captures the EC and could execute inline.
669             TaskCompletionSource<ApplicationResumeStateContainer> tcs = new TaskCompletionSource<ApplicationResumeStateContainer>();
670             ThreadPool.UnsafeQueueUserWorkItem(_ => {
671
672                 // We're not locking on the appDomainContext here. The reason for this is two-fold:
673                 // a) We don't want to cause a potential deadlock issue whereby Suspend could kick
674                 //    off user code that tries calling InitiateShutdown and thus taking a lock on
675                 //    appDomainContext.
676                 // b) It's easier to try calling into the captured HostingEnvironment and just
677                 //    ---- the "no AD" exception than it is to try to synchronize the Suspend,
678                 //    Resume, and Stop methods. The CLR protects us from ourselves here.
679                 //
680                 // We need to use the captured 'hostEnv' to prevent null refs.
681
682                 IntPtr state;
683                 try {
684                     state = hostEnv.SuspendApplication();
685                 }
686                 catch (AppDomainUnloadedException) {
687                     // AD unloads aren't considered a failure
688                     tcs.TrySetResult(null);
689                     return;
690                 }
691
692                 tcs.TrySetResult(new ApplicationResumeStateContainer(hostEnv, state));
693             }, null);
694             return tcs.Task;
695         }
696
697         internal void ResumeAllApplications(object state) {
698             foreach (var resumeContainer in (ApplicationResumeStateContainer[])state) {
699                 if (resumeContainer != null) { // could be null if the application went away
700                     resumeContainer.Resume();
701                 }
702             }
703         }
704
705         //
706         // ping implementation
707         //
708
709         // called from process host
710         internal void Ping(IProcessPingCallback callback) {
711             if (callback == null || _pendingPingCallback != null)
712                 return;
713
714             // remember active callback but only if none is remembered already
715             if (Interlocked.CompareExchange(ref _pendingPingCallback, callback, null) == null) {
716                 // queue a work item to respond to ping
717                 ThreadPool.QueueUserWorkItem(_onRespondToPingWaitCallback);
718             }
719         }
720
721         // threadpool callback (also called on some activity from hosting environment)
722         internal void OnRespondToPingWaitCallback(Object state) {
723             RespondToPingIfNeeded();
724         }
725
726         // respond to ping on callback
727         internal void RespondToPingIfNeeded() {
728             IProcessPingCallback callback = _pendingPingCallback as IProcessPingCallback;
729
730             // make sure we call the callback once
731             if (callback != null) {
732                 if (Interlocked.CompareExchange(ref _pendingPingCallback, null, callback) == callback) {
733                     callback.Respond();
734                 }
735             }
736         }
737
738         // ApplicationManager is loaded into the default AppDomain
739         // ASP.NET doesn't set string hash randomization for the defaul AppDomain, so we can assume the existing CLR implementation here is unchanged
740         // Note, it won't work if <runtime/UseRandomizedStringHashAlgorithm enabled="1"> is used, because the entire process is subject to string hash randomization
741         internal int GetNonRandomizedStringComparerHashCode(string s, bool ignoreCase) { 
742             StringComparer comparer = ignoreCase ? StringComparer.InvariantCultureIgnoreCase : StringComparer.InvariantCulture;
743             return comparer.GetHashCode(s);
744         }
745
746         //
747         // communication with hosting environments
748         //
749
750         internal void HostingEnvironmentActivated(long privateBytesLimit) {
751             int count = Interlocked.Increment(ref _activeHostingEnvCount);
752             
753             // initialize CacheManager once, without blocking
754             if (count == 1) {
755                 InitCacheManager(privateBytesLimit);
756             }
757         }
758
759         internal void HostingEnvironmentShutdownComplete(String appId, IApplicationHost appHost) {
760             try {
761                 if (appHost != null) {
762                     // make sure application host can be GC'd
763                     MarshalByRefObject realApplicationHost = appHost as MarshalByRefObject;
764                     if (realApplicationHost != null) {
765                         RemotingServices.Disconnect(realApplicationHost);
766                     }
767                 }
768             }
769             finally {
770                 Interlocked.Decrement(ref _activeHostingEnvCount);
771             }
772         }
773
774         internal void HostingEnvironmentShutdownInitiated(String appId, HostingEnvironment env) {
775             if (!_shutdownInProgress) { // don't bother during shutdown (while enumerating)
776                 LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
777
778                 lock (ac){
779                     if (!env.HasBeenRemovedFromAppManagerTable) {
780                         env.HasBeenRemovedFromAppManagerTable = true;
781
782                         ac.HostEnv = null;
783                         Interlocked.Decrement(ref _accessibleHostingEnvCount);
784
785                         // Autorestart the application right away
786                         if (ac.PreloadContext != null && !ac.RetryingPreload) {
787                             ProcessHost.PreloadApplicationIfNotShuttingdown(appId, ac);
788                         }
789                     }
790                 }
791             }
792         }
793
794         internal int AppDomainsCount {
795             get { return _accessibleHostingEnvCount; }
796         }
797
798
799         internal void ReduceAppDomainsCount(int limit) {
800             // 
801
802
803
804
805             Dictionary<string, LockableAppDomainContext> apps = CloneAppDomainsCollection();
806             while (_accessibleHostingEnvCount >= limit && !_shutdownInProgress)
807             {
808                 LockableAppDomainContext bestCandidateForShutdown = null;
809                 int bestCandidateLruScore = 0;
810                 
811                 foreach (LockableAppDomainContext ac in apps.Values) {
812                     // Don't lock on LockableAppDomainContext before we check that ac.HostEnv != null.
813                     // Otherwise we may end up with a deadlock between 2 app domains trying to unload each other
814                     HostingEnvironment h = ac.HostEnv;
815                     if (h == null) {
816                         continue;
817                     }
818                     lock (ac) {
819                         h = ac.HostEnv;
820
821                         // Avoid ---- by checking again under lock
822                         if (h == null) {
823                             continue;
824                         }
825                         int newLruScore = h.LruScore;
826
827                         if (bestCandidateForShutdown == null || bestCandidateForShutdown.HostEnv == null || 
828                                 newLruScore < bestCandidateLruScore) {
829
830                             bestCandidateLruScore = newLruScore;
831                             bestCandidateForShutdown = ac;
832                         }
833                     }
834                 }
835
836                 if (bestCandidateForShutdown == null)
837                     break;
838
839                 lock (bestCandidateForShutdown) {
840                     if (bestCandidateForShutdown.HostEnv != null) {
841                         bestCandidateForShutdown.HostEnv.InitiateShutdownInternal();
842                     }
843                 }
844             }
845         }
846
847         //
848         // helper to support legacy APIs (AppHost.CreateAppHost)
849         //
850
851         internal ObjectHandle CreateInstanceInNewWorkerAppDomain(
852                                 Type type,
853                                 String appId,
854                                 VirtualPath virtualPath,
855                                 String physicalPath) {
856
857             Debug.Trace("AppManager", "CreateObjectInNewWorkerAppDomain, type=" + type.FullName);
858
859             IApplicationHost appHost = new SimpleApplicationHost(virtualPath, physicalPath);
860
861             HostingEnvironmentParameters hostingParameters = new HostingEnvironmentParameters();
862             hostingParameters.HostingFlags = HostingEnvironmentFlags.HideFromAppManager;
863
864             HostingEnvironment env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
865             // When marshaling Type, the AppDomain must have FileIoPermission to the assembly, which is not
866             // always the case, so we marshal the assembly qualified name instead
867             return env.CreateInstance(type.AssemblyQualifiedName);
868         }
869
870         //
871         // helpers to facilitate app domain creation
872         //
873         private HostingEnvironment GetAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters) {
874             LockableAppDomainContext ac = GetLockableAppDomainContext (appId);
875
876             lock (ac) {
877                 HostingEnvironment env = ac.HostEnv;
878
879                 if (env != null) {
880                     try {
881                         env.IsUnloaded();
882                     } catch(AppDomainUnloadedException) {
883                         env = null;
884                     }
885                 }
886                 if (env == null) {
887                     env = CreateAppDomainWithHostingEnvironmentAndReportErrors(appId, appHost, hostingParameters);
888                     ac.HostEnv = env;
889                     Interlocked.Increment(ref _accessibleHostingEnvCount);
890                 }
891
892                 return env;
893             }
894            
895         }
896
897         private HostingEnvironment CreateAppDomainWithHostingEnvironmentAndReportErrors(
898                                         String appId,
899                                         IApplicationHost appHost,
900                                         HostingEnvironmentParameters hostingParameters) {
901             try {
902                 return CreateAppDomainWithHostingEnvironment(appId, appHost, hostingParameters);
903             }
904             catch (Exception e) {
905                 Misc.ReportUnhandledException(e, new string[] {SR.GetString(SR.Failed_to_initialize_AppDomain), appId});
906                 throw;
907             }
908         }
909
910         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control the callers.")]
911         [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Boolean.TryParse(System.String,System.Boolean@)", Justification = "Sets parameter to default(bool) on conversion failure, which is semantic we need.")]
912         private HostingEnvironment CreateAppDomainWithHostingEnvironment(
913                                                 String appId,
914                                                 IApplicationHost appHost,
915                                                 HostingEnvironmentParameters hostingParameters) {
916
917             String physicalPath = appHost.GetPhysicalPath();
918             if (!StringUtil.StringEndsWith(physicalPath, Path.DirectorySeparatorChar))
919                 physicalPath = physicalPath + Path.DirectorySeparatorChar;
920
921             String domainId = ConstructAppDomainId(appId);
922             String appName = (StringUtil.GetStringHashCode(String.Concat(appId.ToLower(CultureInfo.InvariantCulture),
923                 physicalPath.ToLower(CultureInfo.InvariantCulture)))).ToString("x", CultureInfo.InvariantCulture);
924             VirtualPath virtualPath = VirtualPath.Create(appHost.GetVirtualPath());
925
926             Debug.Trace("AppManager", "CreateAppDomainWithHostingEnvironment, path=" + physicalPath + "; appId=" + appId + "; domainId=" + domainId);
927
928             IDictionary bindings = new Hashtable(20);
929             AppDomainSetup setup = new AppDomainSetup();
930             AppDomainSwitches switches = new AppDomainSwitches();
931             PopulateDomainBindings(domainId, appId, appName, physicalPath, virtualPath, setup, bindings);
932
933             //  Create the app domain
934
935             AppDomain appDomain = null;
936             Dictionary<string, object> appDomainAdditionalData = new Dictionary<string, object>();
937             Exception appDomainCreationException = null;
938
939             string siteID = appHost.GetSiteID();
940             string appSegment = virtualPath.VirtualPathStringNoTrailingSlash;
941             bool inClientBuildManager = false;
942             Configuration appConfig = null;
943             PolicyLevel policyLevel = null;
944             PermissionSet permissionSet = null;
945             List<StrongName> fullTrustAssemblies = new List<StrongName>();
946             string[] defaultPartialTrustVisibleAssemblies = new[] { "System.Web, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293",
947                                                                     "System.Web.Extensions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
948                                                                     "System.Web.Abstractions, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
949                                                                     "System.Web.Routing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
950                                                                     "System.Web.DynamicData, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
951                                                                     "System.Web.DataVisualization, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9",
952                                                                     "System.Web.ApplicationServices, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" };
953
954             Exception appDomainStartupConfigurationException = null;
955             ImpersonationContext ictxConfig = null;
956             IntPtr uncTokenConfig = IntPtr.Zero;
957             HostingEnvironmentFlags hostingFlags = HostingEnvironmentFlags.Default;
958             if (hostingParameters != null) {
959                 hostingFlags = hostingParameters.HostingFlags;
960                 if ((hostingFlags & HostingEnvironmentFlags.ClientBuildManager) != 0) {
961                     inClientBuildManager = true;
962                     // The default hosting policy in VS has changed (from MultiDomainHost to MultiDomain), 
963                     // so we need to specify explicitly to allow generated assemblies 
964                     // to be unloaded subsequently. (Dev10 bug)
965                     setup.LoaderOptimization = LoaderOptimization.MultiDomainHost;
966                 }
967             }
968             try {
969                 bool requireHostExecutionContextManager = false;
970                 bool requireHostSecurityManager = false;
971
972                 uncTokenConfig = appHost.GetConfigToken();
973                 if (uncTokenConfig != IntPtr.Zero) {
974                     ictxConfig = new ImpersonationContext(uncTokenConfig);
975                 }
976
977                 try {
978                     // Did the custom loader fail to load?
979                     ExceptionDispatchInfo customLoaderException = ProcessHost.GetExistingCustomLoaderFailureAndClear(appId);
980                     if (customLoaderException != null) {
981                         customLoaderException.Throw();
982                     }
983
984                     // We support randomized string hash code, but not for the default AppDomain
985                     // Don't allow string hash randomization for the defaul AppDomain (i.e. <runtime/UseRandomizedStringHashAlgorithm enabled="1">)
986                     // Application should use AppSettings instead to opt-in.
987                     if (EnvironmentInfo.IsStringHashCodeRandomizationDetected) {
988                         throw new ConfigurationErrorsException(SR.GetString(SR.Require_stable_string_hash_codes));
989                     }
990
991                     bool skipAdditionalConfigChecks = false;
992                     if (inClientBuildManager && hostingParameters.IISExpressVersion != null) {
993                         permissionSet = new PermissionSet(PermissionState.Unrestricted);
994                         setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
995                         appConfig = GetAppConfigIISExpress(siteID, appSegment, hostingParameters.IISExpressVersion);
996                         skipAdditionalConfigChecks = true;
997                     }
998                     else {
999                         //Hosted by IIS, we already have an IISMap.
1000                         if (appHost is ISAPIApplicationHost) {
1001                             string cacheKey = System.Web.Caching.CacheInternal.PrefixMapPath + siteID + virtualPath.VirtualPathString;
1002                             MapPathCacheInfo cacheInfo = (MapPathCacheInfo)HttpRuntime.CacheInternal.Remove(cacheKey);
1003                             appConfig = WebConfigurationManager.OpenWebConfiguration(appSegment, siteID);
1004                         }
1005                         // For non-IIS hosting scenarios, we need to get config map from application host in a generic way.
1006                         else {
1007                             appConfig = GetAppConfigGeneric(appHost, siteID, appSegment, virtualPath, physicalPath);
1008                         }
1009                     }
1010
1011                     HttpRuntimeSection httpRuntimeSection = (HttpRuntimeSection)appConfig.GetSection("system.web/httpRuntime");
1012                     if (httpRuntimeSection == null) {
1013                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "httpRuntime"));
1014                     }
1015
1016                     // DevDiv #403846 - Change certain config defaults if <httpRuntime targetFramework="4.5" /> exists in config.
1017                     // We store this information in the AppDomain data because certain configuration sections (like <compilation>)
1018                     // are loaded before config is "baked" in the child AppDomain, and if we make <compilation> and other sections
1019                     // dependent on <httpRuntime> which may not have been loaded yet, we risk introducing ----s. Putting this value
1020                     // in the AppDomain data guarantees that it is available before the first call to the config system.
1021                     FrameworkName targetFrameworkName = httpRuntimeSection.GetTargetFrameworkName();
1022                     if (targetFrameworkName != null) {
1023                         appDomainAdditionalData[System.Web.Util.BinaryCompatibility.TargetFrameworkKey] = targetFrameworkName;
1024                     }
1025
1026                     if (!skipAdditionalConfigChecks) {
1027                         // DevDiv #71268 - Add <httpRuntime defaultRegexMatchTimeout="HH:MM:SS" /> configuration attribute
1028                         if (httpRuntimeSection.DefaultRegexMatchTimeout != TimeSpan.Zero) {
1029                             appDomainAdditionalData[_regexMatchTimeoutKey] = httpRuntimeSection.DefaultRegexMatchTimeout;
1030                         }
1031
1032                         // DevDiv #258274 - Add support for CLR quirks mode to ASP.NET
1033                         if (targetFrameworkName != null) {
1034                             setup.TargetFrameworkName = targetFrameworkName.ToString();
1035                         }
1036
1037                         // DevDiv #286354 - Having a Task-friendly SynchronizationContext requires overriding the AppDomain's HostExecutionContextManager.
1038                         // DevDiv #403846 - If we can't parse the <appSettings> switch, use the <httpRuntime/targetFramework> setting to determine the default.
1039                         AppSettingsSection appSettingsSection = appConfig.AppSettings;
1040                         KeyValueConfigurationElement useTaskFriendlySynchronizationContextElement = appSettingsSection.Settings["aspnet:UseTaskFriendlySynchronizationContext"];
1041                         if (!(useTaskFriendlySynchronizationContextElement != null && Boolean.TryParse(useTaskFriendlySynchronizationContextElement.Value, out requireHostExecutionContextManager))) {
1042                             requireHostExecutionContextManager = new System.Web.Util.BinaryCompatibility(targetFrameworkName).TargetsAtLeastFramework45 ? true : false;
1043                         }
1044
1045                         // DevDiv #390704 - Add support for randomized string hash algorithm
1046                         KeyValueConfigurationElement useRandomizedStringHashAlgorithmElement = appSettingsSection.Settings["aspnet:UseRandomizedStringHashAlgorithm"];
1047                         bool useRandomizedStringHashAlgorithm = false;
1048                         if (useRandomizedStringHashAlgorithmElement != null && Boolean.TryParse(useRandomizedStringHashAlgorithmElement.Value, out useRandomizedStringHashAlgorithm)) {
1049                             switches.UseRandomizedStringHashAlgorithm = useRandomizedStringHashAlgorithm;
1050                         }
1051
1052                         // DevDiv #1041102 - Allow specifying quirks via <appSettings> switches
1053                         // The keys must begin with "AppContext.SetSwitch" and have a non-zero key name length,
1054                         // and the values must be parseable as Booleans.
1055                         Dictionary<string, bool> clrQuirks = null;
1056                         foreach (KeyValueConfigurationElement element in appSettingsSection.Settings) {
1057                             if (element.Key != null && element.Key.Length > _clrQuirkAppSettingsAppContextPrefix.Length && element.Key.StartsWith(_clrQuirkAppSettingsAppContextPrefix, StringComparison.OrdinalIgnoreCase)) {
1058                                 bool value;
1059                                 if (Boolean.TryParse(element.Value, out value)) {
1060                                     if (clrQuirks == null) {
1061                                         clrQuirks = new Dictionary<string, bool>();
1062                                     }
1063                                     
1064                                     clrQuirks[element.Key.Substring(_clrQuirkAppSettingsAppContextPrefix.Length)] = value;
1065                                 }
1066                             }
1067                         }
1068                         
1069                         if (clrQuirks != null && clrQuirks.Count > 0) {
1070                             if (hostingParameters == null) {
1071                                 hostingParameters = new HostingEnvironmentParameters();
1072                             }
1073                             
1074                             hostingParameters.ClrQuirksSwitches = clrQuirks.ToArray();
1075                         }
1076
1077                         // DevDiv #248126 - Allow configuration of FileChangeMonitor behavior
1078                         if (httpRuntimeSection.FcnMode != FcnMode.NotSet) {
1079                             if (hostingParameters == null) {
1080                                 hostingParameters = new HostingEnvironmentParameters();
1081                             }
1082                             hostingParameters.FcnMode = httpRuntimeSection.FcnMode;
1083                         }
1084
1085                         // DevDiv #322858 - Allow FileChangesMonitor to skip reading DACLs as a perf improvement
1086                         KeyValueConfigurationElement disableFcnDaclReadElement = appSettingsSection.Settings["aspnet:DisableFcnDaclRead"];
1087                         if (disableFcnDaclReadElement != null) {
1088                             bool skipReadingAndCachingDacls;
1089                             Boolean.TryParse(disableFcnDaclReadElement.Value, out skipReadingAndCachingDacls);
1090                             if (skipReadingAndCachingDacls) {
1091                                 if (hostingParameters == null) {
1092                                     hostingParameters = new HostingEnvironmentParameters();
1093                                 }
1094                                 hostingParameters.FcnSkipReadAndCacheDacls = true;
1095                             }
1096                         }
1097
1098                         // If we were launched from a development environment, we might want to enable the application to do things
1099                         // it otherwise wouldn't normally allow, such as enabling an administrative control panel. For security reasons,
1100                         // we only do this check if <deployment retail="false" /> [the default value] is specified, since the
1101                         // <deployment> element can only be set at machine-level in a hosted environment.
1102                         DeploymentSection deploymentSection = (DeploymentSection)appConfig.GetSection("system.web/deployment");
1103                         bool isDevEnvironment = false;
1104                         if (deploymentSection != null && !deploymentSection.Retail && EnvironmentInfo.WasLaunchedFromDevelopmentEnvironment) {
1105                             appDomainAdditionalData[".devEnvironment"] = true;
1106                             isDevEnvironment = true;
1107
1108                             // DevDiv #275724 - Allow LocalDB support in partial trust scenarios
1109                             // Normally LocalDB requires full trust since it's the equivalent of unmanaged code execution. If this is
1110                             // a development environment and not a retail deployment, we can assume that the user developing the
1111                             // application is actually in charge of the host, so we can trust him with LocalDB execution.
1112                             // Technically this also means that the developer could have set <trust level="Full" /> in his application,
1113                             // but he might want to deploy his application on a Medium-trust server and thus test how the rest of his
1114                             // application works in a partial trust environment. (He would use SQL in production, whch is safe in
1115                             // partial trust.)
1116                             appDomainAdditionalData["ALLOW_LOCALDB_IN_PARTIAL_TRUST"] = true;
1117                         }
1118
1119                         TrustSection trustSection = (TrustSection)appConfig.GetSection("system.web/trust");
1120                         if (trustSection == null || String.IsNullOrEmpty(trustSection.Level)) {
1121                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_section_not_present, "trust"));
1122                         }
1123
1124                         switches.UseLegacyCas = trustSection.LegacyCasModel;
1125
1126                         if (inClientBuildManager) {
1127                             permissionSet = new PermissionSet(PermissionState.Unrestricted);
1128                             setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1129                         }
1130                         else {
1131                             if (!switches.UseLegacyCas) {
1132                                 if (trustSection.Level == "Full") {
1133                                     permissionSet = new PermissionSet(PermissionState.Unrestricted);
1134                                     setup.PartialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1135                                 }
1136                                 else {
1137                                     SecurityPolicySection securityPolicySection = (SecurityPolicySection)appConfig.GetSection("system.web/securityPolicy");
1138                                     CompilationSection compilationSection = (CompilationSection)appConfig.GetSection("system.web/compilation");
1139                                     FullTrustAssembliesSection fullTrustAssembliesSection = (FullTrustAssembliesSection)appConfig.GetSection("system.web/fullTrustAssemblies");
1140                                     policyLevel = GetPartialTrustPolicyLevel(trustSection, securityPolicySection, compilationSection, physicalPath, virtualPath, isDevEnvironment);
1141                                     permissionSet = policyLevel.GetNamedPermissionSet(trustSection.PermissionSetName);
1142                                     if (permissionSet == null) {
1143                                         throw new ConfigurationErrorsException(SR.GetString(SR.Permission_set_not_found, trustSection.PermissionSetName));
1144                                     }
1145
1146                                     // read full trust assemblies and populate the strong name list
1147                                     if (fullTrustAssembliesSection != null) {
1148                                         FullTrustAssemblyCollection fullTrustAssembliesCollection = fullTrustAssembliesSection.FullTrustAssemblies;
1149                                         if (fullTrustAssembliesCollection != null) {
1150                                             fullTrustAssemblies.AddRange(from FullTrustAssembly fta in fullTrustAssembliesCollection
1151                                                                          select CreateStrongName(fta.AssemblyName, fta.Version, fta.PublicKey));
1152                                         }
1153                                     }
1154
1155                                     // DevDiv #27645 - We need to add future versions of Microsoft.Web.Infrastructure to <fullTrustAssemblies> so that ASP.NET
1156                                     // can version out-of-band releases. We should only do this if V1 of M.W.I is listed.
1157                                     if (fullTrustAssemblies.Contains(_mwiV1StrongName)) {
1158                                         fullTrustAssemblies.AddRange(CreateFutureMicrosoftWebInfrastructureStrongNames());
1159                                     }
1160
1161                                     // Partial-trust AppDomains using a non-legacy CAS model require our special HostSecurityManager
1162                                     requireHostSecurityManager = true;
1163                                 }
1164                             }
1165                             if (trustSection.Level != "Full") {
1166                                 PartialTrustVisibleAssembliesSection partialTrustVisibleAssembliesSection = (PartialTrustVisibleAssembliesSection)appConfig.GetSection("system.web/partialTrustVisibleAssemblies");
1167                                 string[] partialTrustVisibleAssemblies = null;
1168                                 if (partialTrustVisibleAssembliesSection != null) {
1169                                     PartialTrustVisibleAssemblyCollection partialTrustVisibleAssembliesCollection = partialTrustVisibleAssembliesSection.PartialTrustVisibleAssemblies;
1170                                     if (partialTrustVisibleAssembliesCollection != null && partialTrustVisibleAssembliesCollection.Count != 0) {
1171                                         partialTrustVisibleAssemblies = new string[partialTrustVisibleAssembliesCollection.Count + defaultPartialTrustVisibleAssemblies.Length];
1172                                         for (int i = 0; i < partialTrustVisibleAssembliesCollection.Count; i++) {
1173                                             partialTrustVisibleAssemblies[i] = partialTrustVisibleAssembliesCollection[i].AssemblyName +
1174                                                 ", PublicKey=" +
1175                                                 NormalizePublicKeyBlob(partialTrustVisibleAssembliesCollection[i].PublicKey);
1176                                         }
1177                                         defaultPartialTrustVisibleAssemblies.CopyTo(partialTrustVisibleAssemblies, partialTrustVisibleAssembliesCollection.Count);
1178                                     }
1179                                 }
1180                                 if (partialTrustVisibleAssemblies == null) {
1181                                     partialTrustVisibleAssemblies = defaultPartialTrustVisibleAssemblies;
1182                                 }
1183                                 setup.PartialTrustVisibleAssemblies = partialTrustVisibleAssemblies;
1184                             }
1185                         }
1186                     }
1187                 }
1188                 catch (Exception e) {
1189                     appDomainStartupConfigurationException = e;
1190                     permissionSet = new PermissionSet(PermissionState.Unrestricted);
1191                 }
1192
1193                 // Set the AppDomainManager if needed
1194                 Type appDomainManagerType = AspNetAppDomainManager.GetAspNetAppDomainManagerType(requireHostExecutionContextManager, requireHostSecurityManager);
1195                 if (appDomainManagerType != null) {
1196                     setup.AppDomainManagerType = appDomainManagerType.FullName;
1197                     setup.AppDomainManagerAssembly = appDomainManagerType.Assembly.FullName;
1198                 }
1199
1200                 // Apply compatibility switches
1201                 switches.Apply(setup);
1202
1203                 try {
1204                     if (switches.UseLegacyCas) {
1205                         appDomain = AppDomain.CreateDomain(domainId,
1206 #if FEATURE_PAL // FEATURE_PAL: hack to avoid non-supported hosting features
1207                                                            null,
1208 #else // FEATURE_PAL
1209 GetDefaultDomainIdentity(),
1210 #endif // FEATURE_PAL
1211 setup);
1212                     }
1213                     else {
1214                         appDomain = AppDomain.CreateDomain(domainId,
1215 #if FEATURE_PAL // FEATURE_PAL: hack to avoid non-supported hosting features
1216                                                            null,
1217 #else // FEATURE_PAL
1218 GetDefaultDomainIdentity(),
1219 #endif // FEATURE_PAL
1220 setup,
1221                                                            permissionSet,
1222                                                            fullTrustAssemblies.ToArray() /* fully trusted assemblies list: empty list means only trust GAC assemblies */);
1223                     }
1224                     foreach (DictionaryEntry e in bindings)
1225                         appDomain.SetData((String)e.Key, (String)e.Value);
1226                     foreach (var entry in appDomainAdditionalData)
1227                         appDomain.SetData(entry.Key, entry.Value);
1228                 }
1229                 catch (Exception e) {
1230                     Debug.Trace("AppManager", "AppDomain.CreateDomain failed", e);
1231                     appDomainCreationException = e;
1232                 }
1233             }
1234             finally {
1235                 if (ictxConfig != null) {
1236                     ictxConfig.Undo();
1237                     ictxConfig = null;
1238                 }
1239                 if (uncTokenConfig != IntPtr.Zero) {
1240                     UnsafeNativeMethods.CloseHandle(uncTokenConfig);
1241                     uncTokenConfig = IntPtr.Zero;
1242                 }
1243             }
1244
1245             if (appDomain == null) {
1246                 throw new SystemException(SR.GetString(SR.Cannot_create_AppDomain), appDomainCreationException);
1247             }
1248
1249             // Create hosting environment in the new app domain
1250
1251             Type hostType = typeof(HostingEnvironment);
1252             String module = hostType.Module.Assembly.FullName;
1253             String typeName = hostType.FullName;
1254             ObjectHandle h = null;
1255
1256             // impersonate UNC identity, if any
1257             ImpersonationContext ictx = null;
1258             IntPtr uncToken = IntPtr.Zero;
1259
1260             //
1261             // fetching config can fail due to a ---- with the 
1262             // native config reader
1263             // if that has happened, force a flush
1264             //
1265             int maxRetries = 10;
1266             int numRetries = 0;
1267
1268             while (numRetries < maxRetries) {
1269                 try {
1270                     uncToken = appHost.GetConfigToken();
1271                     // no throw, so break
1272                     break;
1273                 }
1274                 catch (InvalidOperationException) {
1275                     numRetries++;
1276                     System.Threading.Thread.Sleep(250);
1277                 }
1278             }
1279
1280
1281             if (uncToken != IntPtr.Zero) {
1282                 try {
1283                     ictx = new ImpersonationContext(uncToken);
1284                 }
1285                 catch {
1286                 }
1287                 finally {
1288                     UnsafeNativeMethods.CloseHandle(uncToken);
1289                 }
1290             }
1291
1292             try {
1293
1294                 // Create the hosting environment in the app domain
1295 #if DBG
1296                 try {
1297                     h = Activator.CreateInstance(appDomain, module, typeName);
1298                 }
1299                 catch (Exception e) {
1300                     Debug.Trace("AppManager", "appDomain.CreateInstance failed; identity=" + System.Security.Principal.WindowsIdentity.GetCurrent().Name, e);
1301                     throw;
1302                 }
1303 #else
1304                 h = Activator.CreateInstance(appDomain, module, typeName);
1305 #endif
1306             }
1307             finally {
1308                 // revert impersonation
1309                 if (ictx != null)
1310                     ictx.Undo();
1311
1312                 if (h == null) {
1313                     AppDomain.Unload(appDomain);
1314                 }
1315             }
1316
1317             HostingEnvironment env = (h != null) ? h.Unwrap() as HostingEnvironment : null;
1318
1319             if (env == null)
1320                 throw new SystemException(SR.GetString(SR.Cannot_create_HostEnv));
1321
1322             // initialize the hosting environment
1323             IConfigMapPathFactory configMapPathFactory = appHost.GetConfigMapPathFactory();
1324             if (appDomainStartupConfigurationException == null) {
1325                 env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel);
1326             }
1327             else {
1328                 env.Initialize(this, appHost, configMapPathFactory, hostingParameters, policyLevel, appDomainStartupConfigurationException);
1329             }
1330             return env;
1331         }
1332
1333         private static string NormalizePublicKeyBlob(string publicKey) {
1334             StringBuilder sb = new StringBuilder();
1335             for (int i = 0; i < publicKey.Length; i++) {
1336                 if (!Char.IsWhiteSpace(publicKey[i])) {
1337                     sb.Append(publicKey[i]);
1338                 }
1339             }
1340             publicKey = sb.ToString();
1341             return publicKey;
1342         }
1343
1344         private static StrongName CreateStrongName(string assemblyName, string version, string publicKeyString) {
1345             byte[] publicKey = null;
1346             StrongName strongName = null;
1347             publicKeyString = NormalizePublicKeyBlob(publicKeyString);
1348             int publicKeySize = publicKeyString.Length / 2;
1349             publicKey = new byte[publicKeySize];
1350             for (int i = 0; i < publicKeySize; i++) {
1351                 publicKey[i] = Byte.Parse(publicKeyString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture);
1352             }
1353             StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);
1354             strongName = new StrongName(keyBlob, assemblyName, new Version(version));
1355             return strongName;
1356         }
1357
1358         // For various reasons, we can't add any entries to the <fullTrustAssemblies> list until .NET 5, which at the time of this writing is a few
1359         // years out. But since ASP.NET releases projects out-of-band from the .NET Framework as a whole (using Microsoft.Web.Infrasturcture), we
1360         // need to be sure that future versions of M.W.I have the ability to assert full trust. This code works by seeing if M.W.I v1 is in the
1361         // <fullTrustAssemblies> list, and if it is then v2 - v10 are implicitly added. If v1 is not present in the <fTA> list, then we'll not
1362         // treat v2 - v10 as implicitly added. See DevDiv #27645 for more information.
1363
1364         private static StrongName GetMicrosoftWebInfrastructureV1StrongName() {
1365             return CreateStrongName(
1366                     assemblyName: "Microsoft.Web.Infrastructure",
1367                     version: "1.0.0.0",
1368                     publicKeyString: "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9");
1369         }
1370
1371         private static IEnumerable<StrongName> CreateFutureMicrosoftWebInfrastructureStrongNames() {
1372             string asmName = _mwiV1StrongName.Name;
1373             StrongNamePublicKeyBlob publicKey = _mwiV1StrongName.PublicKey;
1374             for (int i = 2; i <= 10; i++) {
1375                 yield return new StrongName(publicKey, asmName, new Version(i, 0, 0, 0));
1376             }
1377         }
1378
1379
1380          // devdiv 1038337: execution permission cannot be acquired under partial trust with ctrl-f5.
1381          // We build the codegen path in default domain. In order to build the right path, 
1382          // caller must pass in a flag indicating whether it is under dev environment.
1383         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control this method's caller.")]
1384         private static PolicyLevel GetPartialTrustPolicyLevel(
1385                 TrustSection trustSection, SecurityPolicySection securityPolicySection,
1386                 CompilationSection compilationSection, string physicalPath, VirtualPath virtualPath, bool isDevEnvironment) {
1387             if (securityPolicySection == null || securityPolicySection.TrustLevels[trustSection.Level] == null) {
1388                 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level), String.Empty, 0);
1389             }
1390             String configFile = (String)securityPolicySection.TrustLevels[trustSection.Level].PolicyFileExpanded;
1391             if (configFile == null || !FileUtil.FileExists(configFile)) {
1392                 throw new HttpException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
1393             }
1394             PolicyLevel policyLevel = null;
1395             String appDir = FileUtil.RemoveTrailingDirectoryBackSlash(physicalPath);
1396             String appDirUrl = HttpRuntime.MakeFileUrl(appDir);
1397
1398             // setup $CodeGen$ replacement
1399             string tempDirectory = null;
1400             // These variables are used for error handling
1401             string tempDirAttribName = null;
1402             string configFileName = null;
1403             int configLineNumber = 0;
1404             if (compilationSection != null && !String.IsNullOrEmpty(compilationSection.TempDirectory)) {
1405                 tempDirectory = compilationSection.TempDirectory;
1406                 compilationSection.GetTempDirectoryErrorInfo(out tempDirAttribName,
1407                     out configFileName, out configLineNumber);
1408             }
1409             if (tempDirectory != null) {
1410                 tempDirectory = tempDirectory.Trim();
1411                 if (!Path.IsPathRooted(tempDirectory)) {
1412                     // Make sure the path is not relative (VSWhidbey 260075)
1413                     tempDirectory = null;
1414                 }
1415                 else {
1416                     try {
1417                         // Canonicalize it to avoid problems with spaces (VSWhidbey 229873)
1418                         tempDirectory = new DirectoryInfo(tempDirectory).FullName;
1419                     }
1420                     catch {
1421                         tempDirectory = null;
1422                     }
1423                 }
1424                 if (tempDirectory == null) {
1425                     throw new ConfigurationErrorsException(
1426                         SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
1427                         configFileName, configLineNumber);
1428                 }
1429                 // Create the config-specified directory if needed
1430                 try {
1431                     Directory.CreateDirectory(tempDirectory);
1432                 }
1433                 catch (Exception e) {
1434                     throw new ConfigurationErrorsException(
1435                         SR.GetString(SR.Invalid_temp_directory, tempDirAttribName),
1436                         e,
1437                         configFileName, configLineNumber);
1438                 }
1439             }
1440             else {
1441                 tempDirectory = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), HttpRuntime.codegenDirName);
1442             }
1443             // If we don't have write access to the codegen dir, use the TEMP dir instead.
1444             // This will allow non-admin users to work in hosting scenarios (e.g. Venus, aspnet_compiler)
1445             if (!System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory)) {
1446                 // Don't do this if we're in a service (!UserInteractive), as TEMP
1447                 // could point to unwanted places.
1448                 if (!Environment.UserInteractive) {
1449                     throw new HttpException(SR.GetString(SR.No_codegen_access,
1450                         System.Web.UI.Util.GetCurrentAccountName(), tempDirectory));
1451                 }
1452                 tempDirectory = Path.GetTempPath();
1453                 Debug.Assert(System.Web.UI.Util.HasWriteAccessToDirectory(tempDirectory));
1454                 tempDirectory = Path.Combine(tempDirectory, HttpRuntime.codegenDirName);
1455             }
1456             String simpleAppName = System.Web.Hosting.AppManagerAppDomainFactory.ConstructSimpleAppName(
1457                 VirtualPath.GetVirtualPathStringNoTrailingSlash(virtualPath), isDevEnvironment);
1458             String binDir = Path.Combine(tempDirectory, simpleAppName);
1459             binDir = FileUtil.RemoveTrailingDirectoryBackSlash(binDir);
1460             String binDirUrl = HttpRuntime.MakeFileUrl(binDir);
1461
1462             String originUrl = trustSection.OriginUrl;
1463             FileStream file = new FileStream(configFile, FileMode.Open, FileAccess.Read);
1464             StreamReader reader = new StreamReader(file, Encoding.UTF8);
1465             String strFileData = reader.ReadToEnd();
1466             reader.Close();
1467             strFileData = strFileData.Replace("$AppDir$", appDir);
1468             strFileData = strFileData.Replace("$AppDirUrl$", appDirUrl);
1469             strFileData = strFileData.Replace("$CodeGen$", binDirUrl);
1470             if (originUrl == null)
1471                 originUrl = String.Empty;
1472             strFileData = strFileData.Replace("$OriginHost$", originUrl);
1473             String gacLocation = null;
1474             if (strFileData.IndexOf("$Gac$", StringComparison.Ordinal) != -1) {
1475                 gacLocation = HttpRuntime.GetGacLocation();
1476                 if (gacLocation != null)
1477                     gacLocation = HttpRuntime.MakeFileUrl(gacLocation);
1478                 if (gacLocation == null)
1479                     gacLocation = String.Empty;
1480                 strFileData = strFileData.Replace("$Gac$", gacLocation);
1481             }
1482 #pragma warning disable 618 // ASP is reading their grant set out of legacy policy level files
1483             policyLevel = SecurityManager.LoadPolicyLevelFromString(strFileData, PolicyLevelType.AppDomain);
1484             if (policyLevel == null) {
1485                 throw new ConfigurationErrorsException(SR.GetString(SR.Unable_to_get_policy_file, trustSection.Level));
1486             }
1487             // Found GAC Token
1488             if (gacLocation != null) {
1489                 // walk the code groups at the app domain level and look for one that grants
1490                 // access to the GAC with an UrlMembershipCondition.
1491                 CodeGroup rootGroup = policyLevel.RootCodeGroup;
1492                 bool foundGacCondition = false;
1493                 foreach (CodeGroup childGroup in rootGroup.Children) {
1494                     if (childGroup.MembershipCondition is GacMembershipCondition) {
1495                         foundGacCondition = true;
1496                         // if we found the GAC token and also have the GacMembershipCondition
1497                         // the policy file needs to be upgraded to just include the GacMembershipCondition
1498                         Debug.Assert(!foundGacCondition);
1499                         break;
1500                     }
1501                 }
1502                 // add one as a child of the toplevel group after
1503                 // some sanity checking to make sure it's an ASP.NET policy file
1504                 // which always begins with a FirstMatchCodeGroup granting nothing
1505                 // this might not upgrade some custom policy files
1506                 if (!foundGacCondition) {
1507                     if (rootGroup is FirstMatchCodeGroup) {
1508                         FirstMatchCodeGroup firstMatch = (FirstMatchCodeGroup)rootGroup;
1509                         if (firstMatch.MembershipCondition is AllMembershipCondition &&
1510                             firstMatch.PermissionSetName == "Nothing") {
1511                             PermissionSet fullTrust = new PermissionSet(PermissionState.Unrestricted);
1512                             CodeGroup gacGroup = new UnionCodeGroup(new GacMembershipCondition(),
1513                                                                     new PolicyStatement(fullTrust));
1514                             // now, walk the current groups and insert our new group immediately before the old Gac group
1515                             // we'll need to use heuristics for this: it will be an UrlMembershipCondition group with full trust
1516                             CodeGroup newRoot = new FirstMatchCodeGroup(rootGroup.MembershipCondition, rootGroup.PolicyStatement);
1517                             foreach (CodeGroup childGroup in rootGroup.Children) {
1518                                 // is this the target old $Gac$ group?
1519                                 // insert our new GacMembershipCondition group ahead of it
1520                                 if ((childGroup is UnionCodeGroup) &&
1521                                     (childGroup.MembershipCondition is UrlMembershipCondition) &&
1522                                     childGroup.PolicyStatement.PermissionSet.IsUnrestricted()) {
1523                                     if (null != gacGroup) {
1524                                         newRoot.AddChild(gacGroup);
1525                                         gacGroup = null;
1526                                     }
1527                                 }
1528                                 // append this group to the root group
1529                                 // AddChild itself does a deep Copy to get any
1530                                 // child groups so we don't need one here
1531                                 newRoot.AddChild(childGroup);
1532                             }
1533                             policyLevel.RootCodeGroup = newRoot;
1534                         }
1535                     }
1536                 }
1537             }
1538             return policyLevel;
1539 #pragma warning restore 618
1540         }
1541
1542         private sealed class ApplicationResumeStateContainer {
1543             private static readonly WaitCallback _tpCallback = ResumeCallback;
1544
1545             private readonly HostingEnvironment _hostEnv;
1546             private readonly IntPtr _resumeState;
1547
1548             internal ApplicationResumeStateContainer(HostingEnvironment hostEnv, IntPtr resumeState) {
1549                 _hostEnv = hostEnv;
1550                 _resumeState = resumeState;
1551             }
1552
1553             // schedules resume for execution on a new thread
1554             // unsafe since we don't care about impersonation, identity, etc.
1555             internal void Resume() {
1556                 ThreadPool.UnsafeQueueUserWorkItem(_tpCallback, this);
1557             }
1558
1559             private static void ResumeCallback(object state) {
1560                 ApplicationResumeStateContainer container = (ApplicationResumeStateContainer)state;
1561                 try {
1562                     container._hostEnv.ResumeApplication(container._resumeState);
1563                 }
1564                 catch (AppDomainUnloadedException) {
1565                     // AD unloads aren't considered a failure, ----
1566                 }
1567             }
1568         }
1569
1570         [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)]
1571         private static class AspNetAppDomainManager {
1572             internal static Type GetAspNetAppDomainManagerType(bool overrideHostExecutionContextManager, bool overrideHostSecurityManager) {
1573                 if (!overrideHostExecutionContextManager && !overrideHostSecurityManager) {
1574                     // A custom AppDomainManager isn't necessary for this AppDomain.
1575                     return null;
1576                 }
1577                 else {
1578                     // A custom AppDomainManager is necessary for this AppDomain.
1579                     // See comment on the generic type for further information.
1580                     Type openGenericType = typeof(AspNetAppDomainManagerImpl<,>);
1581                     Type closedGenericType = openGenericType.MakeGenericType(
1582                         (overrideHostExecutionContextManager) ? typeof(AspNetHostExecutionContextManager) : typeof(object),
1583                         (overrideHostSecurityManager) ? typeof(AspNetHostSecurityManager) : typeof(object)
1584                         );
1585                     return closedGenericType;
1586                 }
1587             }
1588
1589             // This AppDomainManager may have been set because we need it for Task support, because this is a partial-trust
1590             // AppDomain, or both. Normally we would store this data in the AppDomain's ambient data store (AppDomain.SetData),
1591             // but the AppDomainManager instance is initialized in the new AppDomain before the original AppDomain has a chance to
1592             // call SetData, so in this AppDomain the call to GetData is useless. However, we can use the AppDomainManager type
1593             // itself to carry the necessary information in the form of a generic type parameter. If a custom
1594             // HostExecutionContextManager or HostSecurityManager is necessary, the generic type parameters can tell us that.
1595             // A generic type parameter of "object" means that this particular sub-manager isn't necessary.
1596             private sealed class AspNetAppDomainManagerImpl<THostExecutionContextManager, THostSecurityManager> : AppDomainManager
1597                 where THostExecutionContextManager : class, new()
1598                 where THostSecurityManager : class, new() {
1599
1600                 private readonly HostExecutionContextManager _hostExecutionContextManager = CreateHostExecutionContextManager();
1601                 private readonly HostSecurityManager _hostSecurityManager = CreateHostSecurityManager();
1602
1603                 public override HostExecutionContextManager HostExecutionContextManager {
1604                     get {
1605                         return _hostExecutionContextManager ?? base.HostExecutionContextManager;
1606                     }
1607                 }
1608
1609                 public override HostSecurityManager HostSecurityManager {
1610                     get {
1611                         return _hostSecurityManager ?? base.HostSecurityManager;
1612                     }
1613                 }
1614
1615                 private static HostExecutionContextManager CreateHostExecutionContextManager() {
1616                     object hostExecutionContextManager = new THostExecutionContextManager();
1617                     Debug.Assert(hostExecutionContextManager is HostExecutionContextManager || hostExecutionContextManager.GetType() == typeof(object), "THostExecutionContextManager was an unexpected type!");
1618                     return hostExecutionContextManager as HostExecutionContextManager;
1619                 }
1620
1621                 private static HostSecurityManager CreateHostSecurityManager() {
1622                     object hostSecurityManager = new THostSecurityManager();
1623                     Debug.Assert(hostSecurityManager is HostSecurityManager || hostSecurityManager.GetType() == typeof(object), "THostSecurityManager was an unexpected type!");
1624                     return hostSecurityManager as HostSecurityManager;
1625                 }
1626             }
1627
1628             private sealed class AspNetHostSecurityManager : HostSecurityManager {
1629                 private PermissionSet Nothing = new PermissionSet(PermissionState.None);
1630                 private PermissionSet FullTrust = new PermissionSet(PermissionState.Unrestricted);
1631                 private HostSecurityPolicyResolver hostSecurityPolicyResolver = null;
1632
1633                 public override HostSecurityManagerOptions Flags {
1634                     get {
1635                         return HostSecurityManagerOptions.HostResolvePolicy;
1636                     }
1637                 }
1638
1639                 [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
1640                 public override PermissionSet ResolvePolicy(Evidence evidence) {
1641                     if (base.ResolvePolicy(evidence).IsUnrestricted()) {
1642                         return FullTrust;
1643                     }
1644
1645                     if (!String.IsNullOrEmpty(HttpRuntime.HostSecurityPolicyResolverType) && hostSecurityPolicyResolver == null) {
1646                         hostSecurityPolicyResolver = Activator.CreateInstance(
1647                             Type.GetType(HttpRuntime.HostSecurityPolicyResolverType)) as HostSecurityPolicyResolver;
1648                     }
1649
1650                     if (hostSecurityPolicyResolver != null) {
1651                         switch (hostSecurityPolicyResolver.ResolvePolicy(evidence)) {
1652                             case HostSecurityPolicyResults.FullTrust:
1653                                 return FullTrust;
1654                             case HostSecurityPolicyResults.AppDomainTrust:
1655                                 return HttpRuntime.NamedPermissionSet;
1656                             case HostSecurityPolicyResults.Nothing:
1657                                 return Nothing;
1658                             case HostSecurityPolicyResults.DefaultPolicy:
1659                                 break;
1660                         }
1661                     }
1662
1663                     if (HttpRuntime.PolicyLevel == null || HttpRuntime.PolicyLevel.Resolve(evidence).PermissionSet.IsUnrestricted())
1664                         return FullTrust;
1665                     else if (HttpRuntime.PolicyLevel.Resolve(evidence).PermissionSet.Equals(Nothing))
1666                         return Nothing;
1667                     else
1668                         return HttpRuntime.NamedPermissionSet;
1669                 }
1670             }
1671         }
1672
1673         private static void PopulateDomainBindings(String domainId, String appId, String appName,
1674                                                     String appPath, VirtualPath appVPath,
1675                                                     AppDomainSetup setup, IDictionary dict) {
1676             // assembly loading settings
1677
1678             // We put both the old and new bin dir names on the private bin path
1679             setup.PrivateBinPathProbe   = "*";  // disable loading from app base
1680             setup.ShadowCopyFiles       = "true";
1681             setup.ApplicationBase       = appPath;
1682             setup.ApplicationName       = appName;
1683             setup.ConfigurationFile     = HttpConfigurationSystem.WebConfigFileName;
1684
1685             // Disallow code download, since it's unreliable in services (ASURT 123836/127606)
1686             setup.DisallowCodeDownload  = true;
1687
1688             // internal settings
1689             dict.Add(".appDomain",     "*");
1690             dict.Add(".appId",         appId);
1691             dict.Add(".appPath",       appPath);
1692             dict.Add(".appVPath",      appVPath.VirtualPathString);
1693             dict.Add(".domainId",      domainId);
1694         }
1695
1696         private static Evidence GetDefaultDomainIdentity() {
1697             Evidence evidence = AppDomain.CurrentDomain.Evidence; // CurrentDomain.Evidence returns a clone so we can modify it if we need
1698             bool hasZone = evidence.GetHostEvidence<Zone>() != null;
1699             bool hasUrl = evidence.GetHostEvidence<Url>() != null;
1700
1701             if (!hasZone)
1702                 evidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));
1703
1704             if (!hasUrl)
1705                 evidence.AddHostEvidence(new Url("ms-internal-microsoft-asp-net-webhost-20"));
1706
1707             return evidence;
1708         }
1709
1710         private static int s_domainCount = 0;
1711         private static Object s_domainCountLock = new Object();
1712
1713         private static String ConstructAppDomainId(String id) {
1714             int domainCount = 0;
1715             lock (s_domainCountLock) {
1716                 domainCount = ++s_domainCount;
1717             }
1718             return id + "-" + domainCount.ToString(NumberFormatInfo.InvariantInfo) + "-" + DateTime.UtcNow.ToFileTime().ToString();
1719         }
1720
1721         internal LockableAppDomainContext GetLockableAppDomainContext (string appId) {
1722             lock (this) {
1723                 LockableAppDomainContext ac;
1724                 if (!_appDomains.TryGetValue(appId, out ac)) {
1725                     ac = new LockableAppDomainContext();
1726                     _appDomains.Add (appId, ac);
1727                 }
1728
1729                 return ac;
1730             }
1731         }
1732
1733         // take a copy of _appDomains collection so that it can be used without locking on ApplicationManager
1734         private Dictionary<string, LockableAppDomainContext> CloneAppDomainsCollection() {
1735             lock (this) {
1736                 return new Dictionary<string, LockableAppDomainContext>(_appDomains, StringComparer.OrdinalIgnoreCase);
1737             }
1738         }
1739
1740         private static Configuration GetAppConfigCommon(IConfigMapPath configMapPath, string siteID, string appSegment) {
1741             WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
1742             string dir = null;
1743             string fileName = null;
1744             string subDir = "/";
1745             // add root mapping
1746             configMapPath.GetPathConfigFilename(siteID, subDir, out dir, out fileName);
1747             if (dir != null) {
1748                 fileMap.VirtualDirectories.Add(subDir, new VirtualDirectoryMapping(Path.GetFullPath(dir), true));
1749             }
1750             // add subdir mappings
1751             string[] subDirs = appSegment.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
1752             foreach (string s in subDirs) {
1753                 subDir = subDir + s;
1754                 configMapPath.GetPathConfigFilename(siteID, subDir, out dir, out fileName);
1755                 if (dir != null) {
1756                     fileMap.VirtualDirectories.Add(subDir, new VirtualDirectoryMapping(Path.GetFullPath(dir), true));
1757                 }
1758                 subDir = subDir + "/";
1759             }
1760             // open mapped web config for application
1761             return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, appSegment, siteID);
1762         }
1763
1764         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Only ever called by the full-trust parent AppDomain.")]
1765         private static Configuration GetAppConfigGeneric(IApplicationHost appHost, string siteID, string appSegment, VirtualPath virtualPath, string physicalPath) {
1766             WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
1767             IConfigMapPathFactory configMapPathFactory2 = appHost.GetConfigMapPathFactory();
1768             IConfigMapPath configMapPath = configMapPathFactory2.Create(virtualPath.VirtualPathString, physicalPath);
1769             return GetAppConfigCommon(configMapPath, siteID, appSegment);
1770         }
1771
1772         private static Configuration GetAppConfigIISExpress(string siteID, string appSegment, string iisExpressVersion) {
1773             ExpressServerConfig serverConfig = (ExpressServerConfig)ServerConfig.GetDefaultDomainInstance(iisExpressVersion);
1774             return GetAppConfigCommon(serverConfig, siteID, appSegment);
1775         }
1776
1777         private sealed class AppDomainSwitches {
1778             public bool UseLegacyCas;
1779             public bool UseRandomizedStringHashAlgorithm;
1780
1781             public void Apply(AppDomainSetup setup) {
1782                 List<string> switches = new List<string>();
1783
1784                 if (UseLegacyCas) {
1785                     // Enables the AppDomain to use the legacy CAS model for compatibility <trust/legacyCasModel>
1786                     switches.Add("NetFx40_LegacySecurityPolicy");
1787                 }
1788
1789                 if (UseRandomizedStringHashAlgorithm) {
1790                     switches.Add("UseRandomizedStringHashAlgorithm");
1791                 }
1792
1793                 if (switches.Count > 0) {
1794                     setup.SetCompatibilitySwitches(switches);
1795                 }
1796             }
1797         }
1798
1799         // This class holds information about the environment that is hosting ASP.NET. The particular design of this class
1800         // is that the information is computed once and stored, and the methods which compute the information are private.
1801         // This prevents accidental misuse of this type via querying the environment after user code has had a chance to
1802         // run, which could potentially affect the environment itself.
1803         private static class EnvironmentInfo {
1804             public static readonly bool IsStringHashCodeRandomizationDetected = GetIsStringHashCodeRandomizationDetected();
1805             public static readonly bool WasLaunchedFromDevelopmentEnvironment = GetWasLaunchedFromDevelopmentEnvironmentValue();
1806
1807             private static bool GetIsStringHashCodeRandomizationDetected() {
1808                 // known test vector
1809                 return (StringComparer.InvariantCultureIgnoreCase.GetHashCode("The quick brown fox jumps over the lazy dog.") != 0x703e662e);
1810             }
1811
1812             // Visual Studio / WebMatrix will set DEV_ENVIRONMENT=1 when launching an ASP.NET host in a development environment.
1813             private static bool GetWasLaunchedFromDevelopmentEnvironmentValue() {
1814                 try {
1815                     string envVar = Environment.GetEnvironmentVariable("DEV_ENVIRONMENT", EnvironmentVariableTarget.Process);
1816                     return String.Equals(envVar, "1", StringComparison.Ordinal);
1817                 }
1818                 catch {
1819                     // We don't care if we can't read the environment variable; just treat it as not present.
1820                     return false;
1821                 }
1822             }
1823         }
1824
1825     }
1826 }