The Labs \ Source Viewer \ SSCLI \ System.Net \ AutoWebProxyScriptWrapper

  1. //------------------------------------------------------------------------------
  2. // <copyright fieldInfole="_AutoWebProxyScriptWrapper.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. // Two implementations of AutoWebProxyScriptWrapper live in this file. The first uses jscript.dll via COM, the second
  16. // uses Microsoft.JScript using an external AppDomain.
  17. #pragma warning disable 618
  18. #define AUTOPROXY_MANAGED_JSCRIPT
  19. #if !AUTOPROXY_MANAGED_JSCRIPT
  20. namespace System.Net
  21. {
  22.     using System.Net.ComImports;
  23.     using System.Runtime.InteropServices;
  24.     using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
  25.     using System.Threading;
  26.     using System.Reflection;
  27.     using System.Net.Configuration;
  28.     using System.Globalization;
  29.    
  30.     internal class AutoWebProxyScriptWrapper
  31.     {
  32.         const string c_ScriptHelperName = "__AutoWebProxyScriptHelper";
  33.        
  34.         private static TimerThread.Queue s_TimerQueue = TimerThread.CreateQueue(SettingsSectionInternal.Section.ExecutionTimeout);
  35.         private static TimerThread.Callback s_InterruptCallback = new TimerThread.Callback(InterruptCallback);
  36.        
  37.        
  38.         //
  39.         // Methods called by the AutoWebProxyScriptEngine
  40.         //
  41.        
  42.         static internal AutoWebProxyScriptWrapper CreateInstance()
  43.         {
  44.             return new AutoWebProxyScriptWrapper();
  45.         }
  46.        
  47.         internal void Close()
  48.         {
  49.             if (Interlocked.Increment(ref closed) != 1) {
  50.                 return;
  51.             }
  52.            
  53.             GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Close() Closing engine.");
  54.            
  55.             // Time out any running thread.
  56.             TimerThread.Timer timer = activeTimer;
  57.             if (timer != null) {
  58.                 if (timer.Cancel()) {
  59.                     InterruptCallback(timer, 0, this);
  60.                 }
  61.                 activeTimer = null;
  62.             }
  63.            
  64.             jscript.Close();
  65.             jscriptObject = null;
  66.             jscript = null;
  67.             host = null;
  68.             jscriptParser = null;
  69.             dispatch = null;
  70.             script = null;
  71.             scriptText = null;
  72.             lastModified = DateTime.MinValue;
  73.         }
  74.        
  75.         internal string FindProxyForURL(string url, string host)
  76.         {
  77.             if (url == null || host == null) {
  78.                 throw new ArgumentNullException(url == null ? "url" : "host");
  79.             }
  80.             if (closed != 0) {
  81.                 throw new ObjectDisposedException(GetType().Name);
  82.             }
  83.            
  84.             EXCEPINFO exceptionInfo = new EXCEPINFO();
  85.             object result = null;
  86.             jscript.GetCurrentScriptThreadID(out interruptThreadId);
  87.             TimerThread.Timer timer = s_TimerQueue.CreateTimer(s_InterruptCallback, this);
  88.             activeTimer = timer;
  89.             try {
  90.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Calling url:" + url + " host:" + host);
  91.                 result = script.FindProxyForURL(url, host);
  92.             }
  93.             catch (Exception exception) {
  94.                 if (NclUtilities.IsFatal(exception))
  95.                     throw;
  96.                 if (exception is TargetInvocationException) {
  97.                     exception = exception.InnerException;
  98.                 }
  99.                 COMException comException = exception as COMException;
  100.                 if (comException == null || comException.ErrorCode != (int)HRESULT.SCRIPT_E_REPORTED) {
  101.                     throw;
  102.                 }
  103.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Script error:[" + this.host.ExceptionMessage == null ? "" : this.host.ExceptionMessage + "]");
  104.             }
  105.             catch {
  106.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Script error:[Non-CLS Compliant Exception]");
  107.                 throw;
  108.             }
  109.             finally {
  110.                 activeTimer = null;
  111.                 timer.Cancel();
  112.             }
  113.            
  114.             string proxy = result as string;
  115.             if (proxy != null) {
  116.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() found:" + proxy);
  117.                 return proxy;
  118.             }
  119.            
  120.             GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Returning null. result:" + ValidationHelper.ToString(exceptionInfo.bstrDescription) + " result:" + ValidationHelper.ToString(result) + " error:" + ValidationHelper.ToString(exceptionInfo.bstrDescription));
  121.             return null;
  122.         }
  123.        
  124.         internal AutoWebProxyState Compile(Uri engineScriptLocation, string scriptBody, byte[] buffer)
  125.         {
  126.             if (closed != 0) {
  127.                 throw new ObjectDisposedException(GetType().Name);
  128.             }
  129.            
  130.             if (jscriptObject != null) {
  131.                 jscript.Close();
  132.             }
  133.            
  134.             scriptText = null;
  135.             scriptBytes = null;
  136.             jscriptObject = new JScriptEngine();
  137.             jscript = (IActiveScript)jscriptObject;
  138.             host = new ScriptHost();
  139.            
  140.             GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Binding to ScriptHost#" + ValidationHelper.HashString(this));
  141.            
  142.             jscriptParser = new ActiveScriptParseWrapper(jscriptObject);
  143.             jscriptParser.InitNew();
  144.            
  145.             jscript.SetScriptSite(host);
  146.             jscript.SetScriptState(ScriptState.Initialized);
  147.            
  148.             //
  149.             // Inform the script engine that this host implements the IInternetHostSecurityManager interface, which
  150.             // is used to prevent the script code from using any ActiveX objects.
  151.             //
  152.             IObjectSafety objSafety = jscript as IObjectSafety;
  153.             if (objSafety != null) {
  154.                 Guid guid = Guid.Empty;
  155.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Setting up IInternetHostSecurityManager");
  156.                 objSafety.SetInterfaceSafetyOptions(ref guid, ComConstants.INTERFACE_USES_SECURITY_MANAGER, ComConstants.INTERFACE_USES_SECURITY_MANAGER);
  157.                 objSafety = null;
  158.             }
  159.            
  160.             EXCEPINFO exceptionInfo = new EXCEPINFO();
  161.             object result = null;
  162.             try {
  163.                 jscriptParser.ParseScriptText(scriptBody, null, null, null, IntPtr.Zero, 0, ScriptText.IsPersistent | ScriptText.IsVisible, out result, out exceptionInfo);
  164.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() ParseScriptText() success:" + ValidationHelper.ToString(exceptionInfo.bstrDescription) + " result:" + ValidationHelper.ToString(result));
  165.             }
  166.             catch (Exception exception) {
  167.                 if (NclUtilities.IsFatal(exception))
  168.                     throw;
  169.                 if (exception is TargetInvocationException) {
  170.                     exception = exception.InnerException;
  171.                 }
  172.                 COMException comException = exception as COMException;
  173.                 if (comException == null || comException.ErrorCode != (int)HRESULT.SCRIPT_E_REPORTED) {
  174.                     throw;
  175.                 }
  176.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Script load error:[" + host.ExceptionMessage == null ? "" : host.ExceptionMessage + "]");
  177.                 throw new COMException(SR.GetString(SR.net_jscript_load, host.ExceptionMessage), comException.ErrorCode);
  178.             }
  179.             catch {
  180.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Script load error:[Non-CLS Compliant Exception]");
  181.                 throw;
  182.             }
  183.            
  184.             jscript.AddNamedItem(c_ScriptHelperName, ScriptItem.GlobalMembers | ScriptItem.IsPersistent | ScriptItem.IsVisible);
  185.            
  186.             // This part can run global code - time it out if necessary.
  187.             jscript.GetCurrentScriptThreadID(out interruptThreadId);
  188.             TimerThread.Timer timer = s_TimerQueue.CreateTimer(s_InterruptCallback, this);
  189.             activeTimer = timer;
  190.             try {
  191.                 jscript.SetScriptState(ScriptState.Started);
  192.                 jscript.SetScriptState(ScriptState.Connected);
  193.             }
  194.             finally {
  195.                 activeTimer = null;
  196.                 timer.Cancel();
  197.             }
  198.            
  199.             jscript.GetScriptDispatch(null, out script);
  200.             GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Got IDispatch:" + ValidationHelper.ToString(dispatch));
  201.            
  202.             scriptText = scriptBody;
  203.             scriptBytes = buffer;
  204.            
  205.             return AutoWebProxyState.CompilationSuccess;
  206.         }
  207.        
  208.         internal string ScriptBody {
  209.             get { return scriptText; }
  210.         }
  211.        
  212.         internal byte[] Buffer {
  213.             get { return scriptBytes; }
  214.            
  215.             set { scriptBytes = value; }
  216.         }
  217.        
  218.         internal DateTime LastModified {
  219.             get { return lastModified; }
  220.            
  221.             set { lastModified = value; }
  222.         }
  223.        
  224.         private static void InterruptCallback(TimerThread.Timer timer, int timeNoticed, object context)
  225.         {
  226.             AutoWebProxyScriptWrapper pThis = (AutoWebProxyScriptWrapper)context;
  227.             GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback()");
  228.            
  229.             if (!object.ReferenceEquals(timer, pThis.activeTimer)) {
  230.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback() Spurious - returning.");
  231.                 return;
  232.             }
  233.            
  234.             EXCEPINFO exceptionInfo;
  235.             try {
  236.                 pThis.jscript.InterruptScriptThread(pThis.interruptThreadId, out exceptionInfo, 0);
  237.             }
  238.             catch (Exception ex) {
  239.                 if (NclUtilities.IsFatal(ex))
  240.                     throw;
  241.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback() InterruptScriptThread() threw:" + ValidationHelper.ToString(ex));
  242.             }
  243.             catch {
  244.                 GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback() InterruptScriptThread() threw: Non-CLS Compliant Exception");
  245.             }
  246.         }
  247.        
  248.        
  249.         //
  250.         // Privates
  251.         //
  252.        
  253.         private JScriptEngine jscriptObject;
  254.         private IActiveScript jscript;
  255.         private ActiveScriptParseWrapper jscriptParser;
  256.         private ScriptHost host;
  257.         private object dispatch;
  258.         private IScript script;
  259.         private string scriptText;
  260.         private byte[] scriptBytes;
  261.         private DateTime lastModified;
  262.        
  263.         // 'activeTimer' is used to protect the engine from spurious callbacks and when the engine is closed.
  264.         private TimerThread.Timer activeTimer;
  265.         private uint interruptThreadId;
  266.        
  267.         private int closed;
  268.        
  269.        
  270.         // IActiveScriptSite implementation
  271.         private class ScriptHost : IActiveScriptSite, IInternetHostSecurityManager, IOleServiceProvider
  272.         {
  273.             private WebProxyScriptHelper helper = new WebProxyScriptHelper();
  274.             private string exceptionMessage;
  275.            
  276.             internal string ExceptionMessage {
  277.                 get { return exceptionMessage; }
  278.             }
  279.            
  280.             //
  281.             // IActiveScriptSite
  282.             //
  283.            
  284.             public void GetLCID(out int lcid)
  285.             {
  286.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetLCID()");
  287.                 lcid = Thread.CurrentThread.CurrentCulture.LCID;
  288.             }
  289.            
  290.             public void GetItemInfo(string name, ScriptInfo returnMask,             [Out()]
  291.             [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown)]
  292. object[] item,             [Out()]
  293.             [MarshalAs(UnmanagedType.LPArray)]
  294. IntPtr[] typeInfo)
  295.             {
  296.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetItemInfo() name:" + ValidationHelper.ToString(name));
  297.                 if (name == null) {
  298.                     throw new ArgumentNullException("name");
  299.                 }
  300.                
  301.                 if (name != c_ScriptHelperName) {
  302.                     throw new COMException(null, (int)HRESULT.TYPE_E_ELEMENTNOTFOUND);
  303.                 }
  304.                
  305.                 if ((returnMask & ScriptInfo.IUnknown) != 0) {
  306.                     if (item == null) {
  307.                         throw new ArgumentNullException("item");
  308.                     }
  309.                    
  310.                     GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetItemInfo() Setting item.");
  311.                     item[0] = helper;
  312.                 }
  313.                
  314.                 if ((returnMask & ScriptInfo.ITypeInfo) != 0) {
  315.                     if (typeInfo == null) {
  316.                         throw new ArgumentNullException("typeInfo");
  317.                     }
  318.                    
  319.                     typeInfo[0] = IntPtr.Zero;
  320.                 }
  321.                
  322.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetItemInfo() Done.");
  323.             }
  324.            
  325.             public void GetDocVersionString(out string version)
  326.             {
  327.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetDocVersionString()");
  328.                 throw new NotImplementedException();
  329.             }
  330.            
  331.             public void OnScriptTerminate(object result, EXCEPINFO exceptionInfo)
  332.             {
  333.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnScriptTerminate() result:" + ValidationHelper.ToString(result) + " error:" + ValidationHelper.ToString(exceptionInfo.bstrDescription));
  334.             }
  335.            
  336.             public void OnStateChange(ScriptState scriptState)
  337.             {
  338.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnStateChange() state:" + ValidationHelper.ToString(scriptState));
  339.                 if (scriptState == ScriptState.Closed) {
  340.                     helper = null;
  341.                 }
  342.             }
  343.            
  344.             public void OnScriptError(IActiveScriptError scriptError)
  345.             {
  346.                 EXCEPINFO exceptionInfo;
  347.                 uint dummy;
  348.                 uint line;
  349.                 int pos;
  350.                 scriptError.GetExceptionInfo(out exceptionInfo);
  351.                 scriptError.GetSourcePosition(out dummy, out line, out pos);
  352.                 exceptionMessage = exceptionInfo.bstrDescription + " (" + line + "," + pos + ")";
  353.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnScriptError() error:" + ValidationHelper.ToString(exceptionInfo.bstrDescription) + " line:" + line + " pos:" + pos);
  354.             }
  355.            
  356.             public void OnEnterScript()
  357.             {
  358.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnEnterScript()");
  359.             }
  360.            
  361.             public void OnLeaveScript()
  362.             {
  363.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnLeaveScript()");
  364.             }
  365.            
  366.             // IOleServiceProvider methods
  367.            
  368.             public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
  369.             {
  370.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::QueryService(" + guidService.ToString() + ")");
  371.                
  372.                 int hr = (int)HRESULT.E_NOINTERFACE;
  373.                 ppvObject = IntPtr.Zero;
  374.                
  375.                 if (guidService == typeof(IInternetHostSecurityManager).GUID) {
  376.                     IntPtr ppObj = Marshal.GetIUnknownForObject(this);
  377.                     try {
  378.                         hr = Marshal.QueryInterface(ppObj, ref riid, out ppvObject);
  379.                     }
  380.                     finally {
  381.                         Marshal.Release(ppObj);
  382.                     }
  383.                 }
  384.                
  385.                 return hr;
  386.             }
  387.            
  388.             // IInternetHostSecurityManager methods.
  389.             // Implementation based on inetcore\wininet\autoconf\cscpsite.cpp
  390.             // The current implementation disallows all ActiveX control activation from script.
  391.            
  392.             public int GetSecurityId(byte[] pbSecurityId, ref IntPtr pcbSecurityId, IntPtr dwReserved)
  393.             {
  394.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetSecurityId()");
  395.                 return (int)HRESULT.E_NOTIMPL;
  396.             }
  397.            
  398.             public int ProcessUrlAction(int dwAction, int[] pPolicy, int cbPolicy, byte[] pContext, int cbContext, int dwFlags, int dwReserved)
  399.             {
  400.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::ProcessUrlAction()");
  401.                 if (pPolicy != null && cbPolicy >= Marshal.SizeOf(typeof(int))) {
  402.                     pPolicy[0] = (int)UrlPolicy.DisAllow;
  403.                 }
  404.                
  405.                 return (int)HRESULT.S_FALSE;
  406.                 // S_FALSE means the policy != URLPOLICY_ALLOW.
  407.             }
  408.            
  409.             public int QueryCustomPolicy(Guid guidKey, out byte[] ppPolicy, out int pcbPolicy, byte[] pContext, int cbContext, int dwReserved)
  410.             {
  411.                 GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::QueryCustomPolicy()");
  412.                 ppPolicy = null;
  413.                 pcbPolicy = 0;
  414.                 return (int)HRESULT.E_NOTIMPL;
  415.             }
  416.         }
  417.     }
  418. }
  419. #else
  420. namespace System.Net
  421. {
  422.     using System.Collections;
  423.     using System.Reflection;
  424.     using System.Security;
  425.     using System.Security.Policy;
  426.     using System.Security.Permissions;
  427.     using System.Runtime.Remoting;
  428.     using System.Runtime.ConstrainedExecution;
  429.     using System.Runtime.CompilerServices;
  430.     using System.Threading;
  431.    
  432.     // This interface is useless to users. We need it to interact with our Microsoft.JScript helper class.
  433.     public interface IWebProxyScript
  434.     {
  435.         bool Load(Uri scriptLocation, string script, Type helperType);
  436.         string Run(string url, string host);
  437.         void Close();
  438.     }
  439.    
  440.     internal class AutoWebProxyScriptWrapper
  441.     {
  442.         private const string c_appDomainName = "WebProxyScript";
  443.        
  444.         // The index is required for the hashtable because calling GetHashCode() on an unloaded AppDomain throws.
  445.         private int appDomainIndex;
  446.         private AppDomain scriptDomain;
  447.         private IWebProxyScript site;
  448.        
  449.         // s_ExcessAppDomain is a holding spot for the most recently created AppDomain. Until we guarantee it gets
  450.         // into s_AppDomains (or is unloaded), no additional AppDomains can be created, to avoid leaking them.
  451.         private static AppDomain s_ExcessAppDomain;
  452.         private static Hashtable s_AppDomains = new Hashtable();
  453.         private static bool s_CleanedUp;
  454.         private static int s_NextAppDomainIndex;
  455.         private static AppDomainSetup s_AppDomainInfo;
  456.         private static Type s_ProxyScriptHelperType;
  457.         private static Exception s_ProxyScriptHelperLoadError;
  458.         private static object s_ProxyScriptHelperLock = new object();
  459.        
  460.         static AutoWebProxyScriptWrapper()
  461.         {
  462.             AppDomain.CurrentDomain.DomainUnload += new EventHandler(OnDomainUnload);
  463.         }
  464.        
  465.         [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.MemberAccess)]
  466.         [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.TypeInformation)]
  467.         internal AutoWebProxyScriptWrapper()
  468.         {
  469.             GlobalLog.Print("AutoWebProxyScriptWrapper::.ctor() Creating AppDomain: " + c_appDomainName);
  470.            
  471.             Exception exception = null;
  472.             if (s_ProxyScriptHelperLoadError == null && s_ProxyScriptHelperType == null) {
  473.                 lock (s_ProxyScriptHelperLock) {
  474.                     if (s_ProxyScriptHelperLoadError == null && s_ProxyScriptHelperType == null) {
  475.                         // Try to load the type late-bound out of Microsoft.JScript.
  476.                         try {
  477.                             s_ProxyScriptHelperType = Type.GetType("System.Net.VsaWebProxyScript, Microsoft.JScript, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
  478.                         }
  479.                         catch (Exception ex) {
  480.                             exception = ex;
  481.                         }
  482.                        
  483.                         if (s_ProxyScriptHelperType == null) {
  484.                             s_ProxyScriptHelperLoadError = exception == null ? new InternalException() : exception;
  485.                         }
  486.                     }
  487.                 }
  488.             }
  489.            
  490.             if (s_ProxyScriptHelperLoadError != null) {
  491.                 throw new TypeLoadException(SR.GetString(SR.net_cannot_load_proxy_helper), s_ProxyScriptHelperLoadError is InternalException ? null : s_ProxyScriptHelperLoadError);
  492.             }
  493.            
  494.             CreateAppDomain();
  495.            
  496.             exception = null;
  497.             try {
  498.                 GlobalLog.Print("AutoWebProxyScriptWrapper::CreateInstance() Creating Object. type.Assembly.FullName: [" + s_ProxyScriptHelperType.Assembly.FullName + "] type.FullName: [" + s_ProxyScriptHelperType.FullName + "]");
  499.                 ObjectHandle handle = Activator.CreateInstance(scriptDomain, s_ProxyScriptHelperType.Assembly.FullName, s_ProxyScriptHelperType.FullName, false, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null, null, null
  500.                 );
  501.                 if (handle != null) {
  502.                     site = (IWebProxyScript)handle.Unwrap();
  503.                 }
  504.                 GlobalLog.Print("AutoWebProxyScriptWrapper::CreateInstance() Create script site:" + ValidationHelper.HashString(site));
  505.             }
  506.             catch (Exception ex) {
  507.                 exception = ex;
  508.             }
  509.             if (site == null) {
  510.                 lock (s_ProxyScriptHelperLock) {
  511.                     if (s_ProxyScriptHelperLoadError == null) {
  512.                         s_ProxyScriptHelperLoadError = exception == null ? new InternalException() : exception;
  513.                     }
  514.                 }
  515.                 throw new TypeLoadException(SR.GetString(SR.net_cannot_load_proxy_helper), s_ProxyScriptHelperLoadError is InternalException ? null : s_ProxyScriptHelperLoadError);
  516.             }
  517.         }
  518.        
  519.         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
  520.         private void CreateAppDomain()
  521.         {
  522.             // Locking s_AppDomains must happen in a CER so we don't orphan a lock that gets taken by AppDomain.DomainUnload.
  523.             bool lockHeld = false;
  524.             RuntimeHelpers.PrepareConstrainedRegions();
  525.             try {
  526.                 try {
  527.                 }
  528.                 finally {
  529.                     Monitor.Enter(s_AppDomains.SyncRoot);
  530.                     lockHeld = true;
  531.                 }
  532.                
  533.                 if (s_CleanedUp) {
  534.                     throw new InvalidOperationException(SR.GetString(SR.net_cant_perform_during_shutdown));
  535.                 }
  536.                
  537.                 // Create singleton.
  538.                 if (s_AppDomainInfo == null) {
  539.                     s_AppDomainInfo = new AppDomainSetup();
  540.                     s_AppDomainInfo.DisallowBindingRedirects = true;
  541.                     s_AppDomainInfo.DisallowCodeDownload = true;
  542.                    
  543.                     NamedPermissionSet perms = new NamedPermissionSet("__WebProxySandbox", PermissionState.None);
  544.                     perms.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
  545.                 }
  546.                
  547.                 // If something's already in s_ExcessAppDomain, try to dislodge it again.
  548.                 AppDomain excessAppDomain = s_ExcessAppDomain;
  549.                 if (excessAppDomain != null) {
  550.                     TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), excessAppDomain);
  551.                     throw new InvalidOperationException(SR.GetString(SR.net_cant_create_environment));
  552.                 }
  553.                
  554.                 appDomainIndex = s_NextAppDomainIndex++;
  555.                 try {
  556.                 }
  557.                 finally {
  558.                     //
  559.                     s_ExcessAppDomain = AppDomain.CreateDomain(c_appDomainName, null, s_AppDomainInfo);
  560.                    
  561.                     try {
  562.                         s_AppDomains.Add(appDomainIndex, s_ExcessAppDomain);
  563.                        
  564.                         // This indicates to the finally and the finalizer that everything succeeded.
  565.                         scriptDomain = s_ExcessAppDomain;
  566.                     }
  567.                     finally {
  568.                         // ReferenceEquals has a ReliabilityContract.
  569.                         if (object.ReferenceEquals(scriptDomain, s_ExcessAppDomain)) {
  570.                             s_ExcessAppDomain = null;
  571.                         }
  572.                         else {
  573.                             // Something failed. Leave the domain in s_ExcessAppDomain until we can get rid of it. No
  574.                             // more AppDomains can be created until we do. In the mean time, keep attempting to get the
  575.                             // TimerThread to remove it. Also, might as well remove it from the hash if it made it in.
  576.                             try {
  577.                                 s_AppDomains.Remove(appDomainIndex);
  578.                             }
  579.                             finally {
  580.                                 // Can't call AppDomain.Unload from a user thread (or in a lock).
  581.                                 TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), s_ExcessAppDomain);
  582.                             }
  583.                         }
  584.                     }
  585.                 }
  586.             }
  587.             finally {
  588.                 if (lockHeld) {
  589.                     Monitor.Exit(s_AppDomains.SyncRoot);
  590.                 }
  591.             }
  592.         }
  593.        
  594.         internal void Close()
  595.         {
  596.             site.Close();
  597.            
  598.             // Can't call AppDomain.Unload() from a user thread.
  599.             TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), appDomainIndex);
  600.             GC.SuppressFinalize(this);
  601.         }
  602.        
  603.         // Bug 434828
  604.         //
  605.         // It's very hard to guarantee cleanup of an AppDomain. They aren't garbage collected, and Unload() is synchronous and
  606.         // can't be called from the finalizer thread. So we must have a finalizer that uses another thread, in this case the
  607.         // TimerThread, to unload the domain.
  608.         //
  609.         // A case this will come up is if the user replaces the DefaultWebProxy. The old one will be GC'd - there's no chance to
  610.         // clean it up properly. If the user wants to avoid the TimerThread being spun up for that purpose, they should save the
  611.         // existing DefaultWebProxy in a static before replacing it.
  612.         ~AutoWebProxyScriptWrapper()
  613.         {
  614.             if (!NclUtilities.HasShutdownStarted && scriptDomain != null) {
  615.                 // Can't call AppDomain.Unload() from the finalizer thread.
  616.                 TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), appDomainIndex);
  617.             }
  618.         }
  619.        
  620.         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
  621.         private static void CloseAppDomainCallback(TimerThread.Timer timer, int timeNoticed, object context)
  622.         {
  623.             try {
  624.                 AppDomain domain = context as AppDomain;
  625.                 if (domain == null) {
  626.                     CloseAppDomain((int)context);
  627.                 }
  628.                 else {
  629.                     if (object.ReferenceEquals(domain, s_ExcessAppDomain)) {
  630.                         try {
  631.                             AppDomain.Unload(domain);
  632.                         }
  633.                         catch (AppDomainUnloadedException) {
  634.                         }
  635.                         s_ExcessAppDomain = null;
  636.                     }
  637.                 }
  638.             }
  639.             catch (Exception exception) {
  640.                 if (NclUtilities.IsFatal(exception))
  641.                     throw;
  642.             }
  643.         }
  644.        
  645.         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
  646.         private static void CloseAppDomain(int index)
  647.         {
  648.             AppDomain appDomain;
  649.            
  650.             // Locking s_AppDomains must happen in a CER so we don't orphan a lock that gets taken by AppDomain.DomainUnload.
  651.             bool lockHeld = false;
  652.             RuntimeHelpers.PrepareConstrainedRegions();
  653.             try {
  654.                 try {
  655.                 }
  656.                 finally {
  657.                     Monitor.Enter(s_AppDomains.SyncRoot);
  658.                     lockHeld = true;
  659.                 }
  660.                
  661.                 if (s_CleanedUp) {
  662.                     return;
  663.                 }
  664.                 appDomain = (AppDomain)s_AppDomains[index];
  665.             }
  666.             finally {
  667.                 if (lockHeld) {
  668.                     Monitor.Exit(s_AppDomains.SyncRoot);
  669.                     lockHeld = false;
  670.                 }
  671.             }
  672.            
  673.             try {
  674.                 // Cannot call Unload() in a lock shared by OnDomainUnload() - deadlock with ADUnload thread.
  675.                 // So we may try to unload the same domain twice.
  676.                 AppDomain.Unload(appDomain);
  677.             }
  678.             catch (AppDomainUnloadedException) {
  679.             }
  680.             finally {
  681.                 RuntimeHelpers.PrepareConstrainedRegions();
  682.                 try {
  683.                     try {
  684.                     }
  685.                     finally {
  686.                         Monitor.Enter(s_AppDomains.SyncRoot);
  687.                         lockHeld = true;
  688.                     }
  689.                    
  690.                     s_AppDomains.Remove(index);
  691.                 }
  692.                 finally {
  693.                     if (lockHeld) {
  694.                         Monitor.Exit(s_AppDomains.SyncRoot);
  695.                     }
  696.                 }
  697.             }
  698.         }
  699.        
  700.         [ReliabilityContract(Consistency.MayCorruptProcess, Cer.MayFail)]
  701.         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
  702.         private static void OnDomainUnload(object sender, EventArgs e)
  703.         {
  704.             lock (s_AppDomains.SyncRoot) {
  705.                 if (!s_CleanedUp) {
  706.                     s_CleanedUp = true;
  707.                     foreach (AppDomain domain in s_AppDomains.Values) {
  708.                         try {
  709.                             AppDomain.Unload(domain);
  710.                         }
  711.                         catch {
  712.                         }
  713.                     }
  714.                     s_AppDomains.Clear();
  715.                     AppDomain excessAppDomain = s_ExcessAppDomain;
  716.                     if (excessAppDomain != null) {
  717.                         try {
  718.                             AppDomain.Unload(excessAppDomain);
  719.                         }
  720.                         catch {
  721.                         }
  722.                         s_ExcessAppDomain = null;
  723.                     }
  724.                 }
  725.             }
  726.         }
  727.        
  728.         internal string ScriptBody {
  729.             get { return scriptText; }
  730.         }
  731.        
  732.         internal byte[] Buffer {
  733.             get { return scriptBytes; }
  734.            
  735.             set { scriptBytes = value; }
  736.         }
  737.        
  738.         internal DateTime LastModified {
  739.             get { return lastModified; }
  740.            
  741.             set { lastModified = value; }
  742.         }
  743.        
  744.         private string scriptText;
  745.         private byte[] scriptBytes;
  746.         private DateTime lastModified;
  747.        
  748.         // Forward these to the site.
  749.         internal string FindProxyForURL(string url, string host)
  750.         {
  751.             GlobalLog.Print("AutoWebProxyScriptWrapper::FindProxyForURL() Calling JScript for url:" + url.ToString() + " host:" + host.ToString());
  752.             return site.Run(url, host);
  753.         }
  754.        
  755.         internal AutoWebProxyState Compile(Uri engineScriptLocation, string scriptBody, byte[] buffer)
  756.         {
  757.             if (site.Load(engineScriptLocation, scriptBody, typeof(WebProxyScriptHelper))) {
  758.                 GlobalLog.Print("AutoWebProxyScriptWrapper::Compile() Compilation succeeded for engineScriptLocation:" + engineScriptLocation.ToString());
  759.                 scriptText = scriptBody;
  760.                 scriptBytes = buffer;
  761.                 return AutoWebProxyState.CompilationSuccess;
  762.             }
  763.             GlobalLog.Print("AutoWebProxyScriptWrapper::Compile() Compilation failed for engineScriptLocation:" + engineScriptLocation.ToString());
  764.             return AutoWebProxyState.CompilationFailure;
  765.         }
  766.     }
  767. }
  768. #endif

Developer Fusion