|
//------------------------------------------------------------------------------
// <copyright fieldInfole="_AutoWebProxyScriptWrapper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// Two implementations of AutoWebProxyScriptWrapper live in this file. The first uses jscript.dll via COM, the second
// uses Microsoft.JScript using an external AppDomain.
#pragma warning disable 618
#define AUTOPROXY_MANAGED_JSCRIPT
#if !AUTOPROXY_MANAGED_JSCRIPT
namespace System.Net
{
using System.Net.ComImports;
using System.Runtime.InteropServices;
using EXCEPINFO = System.Runtime.InteropServices.ComTypes.EXCEPINFO;
using System.Threading;
using System.Reflection;
using System.Net.Configuration;
using System.Globalization;
internal class AutoWebProxyScriptWrapper
{
const string c_ScriptHelperName = "__AutoWebProxyScriptHelper";
private static TimerThread.Queue s_TimerQueue = TimerThread.CreateQueue(SettingsSectionInternal.Section.ExecutionTimeout);
private static TimerThread.Callback s_InterruptCallback = new TimerThread.Callback(InterruptCallback);
//
// Methods called by the AutoWebProxyScriptEngine
//
internal static AutoWebProxyScriptWrapper CreateInstance()
{
return new AutoWebProxyScriptWrapper();
}
internal void Close()
{
if (Interlocked.Increment(ref closed) != 1)
{
return;
}
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Close() Closing engine.");
// Time out any running thread.
TimerThread.Timer timer = activeTimer;
if (timer != null)
{
if (timer.Cancel())
{
InterruptCallback(timer, 0, this);
}
activeTimer = null;
}
jscript.Close();
jscriptObject = null;
jscript = null;
host = null;
jscriptParser = null;
dispatch = null;
script = null;
scriptText = null;
lastModified = DateTime.MinValue;
}
internal string FindProxyForURL(string url, string host)
{
if (url == null || host == null)
{
throw new ArgumentNullException(url == null ? "url" : "host");
}
if (closed != 0)
{
throw new ObjectDisposedException(GetType().Name);
}
EXCEPINFO exceptionInfo = new EXCEPINFO();
object result = null;
jscript.GetCurrentScriptThreadID(out interruptThreadId);
TimerThread.Timer timer = s_TimerQueue.CreateTimer(s_InterruptCallback, this);
activeTimer = timer;
try
{
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Calling url:" + url + " host:" + host);
result = script.FindProxyForURL(url, host);
}
catch (Exception exception)
{
if (NclUtilities.IsFatal(exception)) throw;
if (exception is TargetInvocationException)
{
exception = exception.InnerException;
}
COMException comException = exception as COMException;
if (comException == null || comException.ErrorCode != (int) HRESULT.SCRIPT_E_REPORTED)
{
throw;
}
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Script error:[" + this.host.ExceptionMessage == null ? "" : this.host.ExceptionMessage + "]");
}
catch {
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Script error:[Non-CLS Compliant Exception]");
throw;
}
finally
{
activeTimer = null;
timer.Cancel();
}
string proxy = result as string;
if (proxy != null)
{
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() found:" + proxy);
return proxy;
}
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::FindProxyForURL() Returning null. result:" + ValidationHelper.ToString(exceptionInfo.bstrDescription) + " result:" + ValidationHelper.ToString(result) + " error:" + ValidationHelper.ToString(exceptionInfo.bstrDescription));
return null;
}
internal AutoWebProxyState Compile(Uri engineScriptLocation, string scriptBody, byte[] buffer)
{
if (closed != 0)
{
throw new ObjectDisposedException(GetType().Name);
}
if (jscriptObject != null)
{
jscript.Close();
}
scriptText = null;
scriptBytes = null;
jscriptObject = new JScriptEngine();
jscript = (IActiveScript) jscriptObject;
host = new ScriptHost();
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Binding to ScriptHost#" + ValidationHelper.HashString(this));
jscriptParser = new ActiveScriptParseWrapper(jscriptObject);
jscriptParser.InitNew();
jscript.SetScriptSite(host);
jscript.SetScriptState(ScriptState.Initialized);
//
// Inform the script engine that this host implements the IInternetHostSecurityManager interface, which
// is used to prevent the script code from using any ActiveX objects.
//
IObjectSafety objSafety = jscript as IObjectSafety;
if (objSafety != null)
{
Guid guid = Guid.Empty;
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Setting up IInternetHostSecurityManager");
objSafety.SetInterfaceSafetyOptions(ref guid, ComConstants.INTERFACE_USES_SECURITY_MANAGER, ComConstants.INTERFACE_USES_SECURITY_MANAGER);
objSafety = null;
}
EXCEPINFO exceptionInfo = new EXCEPINFO();
object result = null;
try
{
jscriptParser.ParseScriptText(scriptBody, null, null, null, IntPtr.Zero, 0, ScriptText.IsPersistent | ScriptText.IsVisible, out result, out exceptionInfo);
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() ParseScriptText() success:" + ValidationHelper.ToString(exceptionInfo.bstrDescription) + " result:" + ValidationHelper.ToString(result));
}
catch (Exception exception)
{
if (NclUtilities.IsFatal(exception)) throw;
if (exception is TargetInvocationException)
{
exception = exception.InnerException;
}
COMException comException = exception as COMException;
if (comException == null || comException.ErrorCode != (int) HRESULT.SCRIPT_E_REPORTED)
{
throw;
}
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Script load error:[" + host.ExceptionMessage == null ? "" : host.ExceptionMessage + "]");
throw new COMException(SR.GetString(SR.net_jscript_load, host.ExceptionMessage), comException.ErrorCode);
}
catch {
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Script load error:[Non-CLS Compliant Exception]");
throw;
}
jscript.AddNamedItem(c_ScriptHelperName, ScriptItem.GlobalMembers | ScriptItem.IsPersistent | ScriptItem.IsVisible);
// This part can run global code - time it out if necessary.
jscript.GetCurrentScriptThreadID(out interruptThreadId);
TimerThread.Timer timer = s_TimerQueue.CreateTimer(s_InterruptCallback, this);
activeTimer = timer;
try
{
jscript.SetScriptState(ScriptState.Started);
jscript.SetScriptState(ScriptState.Connected);
}
finally
{
activeTimer = null;
timer.Cancel();
}
jscript.GetScriptDispatch(null, out script);
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(this) + "::Compile() Got IDispatch:" + ValidationHelper.ToString(dispatch));
scriptText = scriptBody;
scriptBytes = buffer;
return AutoWebProxyState.CompilationSuccess;
}
internal string ScriptBody
{
get
{
return scriptText;
}
}
internal byte[] Buffer
{
get
{
return scriptBytes;
}
set
{
scriptBytes = value;
}
}
internal DateTime LastModified
{
get
{
return lastModified;
}
set
{
lastModified = value;
}
}
private static void InterruptCallback(TimerThread.Timer timer, int timeNoticed, object context)
{
AutoWebProxyScriptWrapper pThis = (AutoWebProxyScriptWrapper)context;
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback()");
if (!object.ReferenceEquals(timer, pThis.activeTimer))
{
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback() Spurious - returning.");
return;
}
EXCEPINFO exceptionInfo;
try
{
pThis.jscript.InterruptScriptThread(pThis.interruptThreadId, out exceptionInfo, 0);
}
catch (Exception ex)
{
if (NclUtilities.IsFatal(ex)) throw;
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback() InterruptScriptThread() threw:" + ValidationHelper.ToString(ex));
}
catch {
GlobalLog.Print("AutoWebProxyScriptWrapper#" + ValidationHelper.HashString(pThis) + "::InterruptCallback() InterruptScriptThread() threw: Non-CLS Compliant Exception");
}
}
//
// Privates
//
private JScriptEngine jscriptObject;
private IActiveScript jscript;
private ActiveScriptParseWrapper jscriptParser;
private ScriptHost host;
private object dispatch;
private IScript script;
private string scriptText;
private byte[] scriptBytes;
private DateTime lastModified;
// 'activeTimer' is used to protect the engine from spurious callbacks and when the engine is closed.
private TimerThread.Timer activeTimer;
private uint interruptThreadId;
private int closed;
// IActiveScriptSite implementation
private class ScriptHost : IActiveScriptSite, IInternetHostSecurityManager, IOleServiceProvider
{
private WebProxyScriptHelper helper = new WebProxyScriptHelper();
private string exceptionMessage;
internal string ExceptionMessage
{
get
{
return exceptionMessage;
}
}
//
// IActiveScriptSite
//
public void GetLCID(out int lcid)
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetLCID()");
lcid = Thread.CurrentThread.CurrentCulture.LCID;
}
public void GetItemInfo(
string name,
ScriptInfo returnMask,
[Out] [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown)] object[] item,
[Out] [MarshalAs(UnmanagedType.LPArray)] IntPtr[] typeInfo)
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetItemInfo() name:" + ValidationHelper.ToString(name));
if (name == null)
{
throw new ArgumentNullException("name");
}
if (name != c_ScriptHelperName)
{
throw new COMException(null, (int) HRESULT.TYPE_E_ELEMENTNOTFOUND);
}
if ((returnMask & ScriptInfo.IUnknown) != 0)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetItemInfo() Setting item.");
item[0] = helper;
}
if ((returnMask & ScriptInfo.ITypeInfo) != 0)
{
if (typeInfo == null)
{
throw new ArgumentNullException("typeInfo");
}
typeInfo[0] = IntPtr.Zero;
}
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetItemInfo() Done.");
}
public void GetDocVersionString(out string version)
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetDocVersionString()");
throw new NotImplementedException();
}
public void OnScriptTerminate(object result, EXCEPINFO exceptionInfo)
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnScriptTerminate() result:" + ValidationHelper.ToString(result) + " error:" + ValidationHelper.ToString(exceptionInfo.bstrDescription));
}
public void OnStateChange(ScriptState scriptState)
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnStateChange() state:" + ValidationHelper.ToString(scriptState));
if (scriptState == ScriptState.Closed)
{
helper = null;
}
}
public void OnScriptError(IActiveScriptError scriptError)
{
EXCEPINFO exceptionInfo;
uint dummy;
uint line;
int pos;
scriptError.GetExceptionInfo(out exceptionInfo);
scriptError.GetSourcePosition(out dummy, out line, out pos);
exceptionMessage = exceptionInfo.bstrDescription + " (" + line + "," + pos + ")";
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnScriptError() error:" + ValidationHelper.ToString(exceptionInfo.bstrDescription) + " line:" + line + " pos:" + pos);
}
public void OnEnterScript()
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnEnterScript()");
}
public void OnLeaveScript()
{
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::OnLeaveScript()");
}
// IOleServiceProvider methods
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject) {
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::QueryService(" + guidService.ToString() + ")");
int hr = (int)HRESULT.E_NOINTERFACE;
ppvObject = IntPtr.Zero;
if (guidService == typeof(IInternetHostSecurityManager).GUID) {
IntPtr ppObj = Marshal.GetIUnknownForObject(this);
try {
hr = Marshal.QueryInterface(ppObj, ref riid, out ppvObject);
}
finally {
Marshal.Release(ppObj);
}
}
return hr;
}
// IInternetHostSecurityManager methods.
// Implementation based on inetcore\wininet\autoconf\cscpsite.cpp
// The current implementation disallows all ActiveX control activation from script.
public int GetSecurityId(byte[] pbSecurityId, ref IntPtr pcbSecurityId, IntPtr dwReserved) {
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::GetSecurityId()");
return (int)HRESULT.E_NOTIMPL;
}
public int ProcessUrlAction(int dwAction, int[] pPolicy, int cbPolicy, byte[] pContext, int cbContext, int dwFlags, int dwReserved) {
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::ProcessUrlAction()");
if (pPolicy != null && cbPolicy >= Marshal.SizeOf(typeof(int))) {
pPolicy[0] = (int)UrlPolicy.DisAllow;
}
return (int)HRESULT.S_FALSE; // S_FALSE means the policy != URLPOLICY_ALLOW.
}
public int QueryCustomPolicy(Guid guidKey, out byte[] ppPolicy, out int pcbPolicy, byte[] pContext, int cbContext, int dwReserved) {
GlobalLog.Print("AutoWebProxyScriptWrapper.ScriptHost#" + ValidationHelper.HashString(this) + "::QueryCustomPolicy()");
ppPolicy = null;
pcbPolicy = 0;
return (int) HRESULT.E_NOTIMPL;
}
}
}
}
#else
namespace System.Net
{
using System.Collections;
using System.Reflection;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;
using System.Runtime.Remoting;
using System.Runtime.ConstrainedExecution;
using System.Runtime.CompilerServices;
using System.Threading;
// This interface is useless to users. We need it to interact with our Microsoft.JScript helper class.
public interface IWebProxyScript
{
bool Load(Uri scriptLocation, string script, Type helperType);
string Run(string url, string host);
void Close();
}
internal class AutoWebProxyScriptWrapper
{
private const string c_appDomainName = "WebProxyScript";
// The index is required for the hashtable because calling GetHashCode() on an unloaded AppDomain throws.
private int appDomainIndex;
private AppDomain scriptDomain;
private IWebProxyScript site;
// s_ExcessAppDomain is a holding spot for the most recently created AppDomain. Until we guarantee it gets
// into s_AppDomains (or is unloaded), no additional AppDomains can be created, to avoid leaking them.
private static volatile AppDomain s_ExcessAppDomain;
private static Hashtable s_AppDomains = new Hashtable();
private static bool s_CleanedUp;
private static int s_NextAppDomainIndex;
private static AppDomainSetup s_AppDomainInfo;
private static volatile Type s_ProxyScriptHelperType;
private static volatile Exception s_ProxyScriptHelperLoadError;
private static object s_ProxyScriptHelperLock = new object();
static AutoWebProxyScriptWrapper()
{
AppDomain.CurrentDomain.DomainUnload += new EventHandler(OnDomainUnload);
}
[ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.MemberAccess)]
[ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.TypeInformation)]
internal AutoWebProxyScriptWrapper()
{
GlobalLog.Print("AutoWebProxyScriptWrapper::.ctor() Creating AppDomain: " + c_appDomainName);
Exception exception = null;
if (s_ProxyScriptHelperLoadError == null && s_ProxyScriptHelperType == null)
{
lock (s_ProxyScriptHelperLock)
{
if (s_ProxyScriptHelperLoadError == null && s_ProxyScriptHelperType == null)
{
// Try to load the type late-bound out of Microsoft.JScript.
try
{
s_ProxyScriptHelperType = Type.GetType("System.Net.VsaWebProxyScript, Microsoft.JScript, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", true);
}
catch (Exception ex)
{
exception = ex;
}
if (s_ProxyScriptHelperType == null)
{
s_ProxyScriptHelperLoadError = exception == null ? new InternalException() : exception;
}
}
}
}
if (s_ProxyScriptHelperLoadError != null)
{
throw new TypeLoadException(SR.GetString(SR.net_cannot_load_proxy_helper), s_ProxyScriptHelperLoadError is InternalException ? null : s_ProxyScriptHelperLoadError);
}
CreateAppDomain();
exception = null;
try
{
GlobalLog.Print("AutoWebProxyScriptWrapper::CreateInstance() Creating Object. type.Assembly.FullName: [" + s_ProxyScriptHelperType.Assembly.FullName + "] type.FullName: [" + s_ProxyScriptHelperType.FullName + "]");
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);
if (handle != null)
{
site = (IWebProxyScript) handle.Unwrap();
}
GlobalLog.Print("AutoWebProxyScriptWrapper::CreateInstance() Create script site:" + ValidationHelper.HashString(site));
}
catch (Exception ex)
{
exception = ex;
}
if (site == null)
{
lock (s_ProxyScriptHelperLock)
{
if (s_ProxyScriptHelperLoadError == null)
{
s_ProxyScriptHelperLoadError = exception == null ? new InternalException() : exception;
}
}
throw new TypeLoadException(SR.GetString(SR.net_cannot_load_proxy_helper), s_ProxyScriptHelperLoadError is InternalException ? null : s_ProxyScriptHelperLoadError);
}
}
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
private void CreateAppDomain()
{
// Locking s_AppDomains must happen in a CER so we don't orphan a lock that gets taken by AppDomain.DomainUnload.
bool lockHeld = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(s_AppDomains.SyncRoot, ref lockHeld);
if (s_CleanedUp)
{
throw new InvalidOperationException(SR.GetString(SR.net_cant_perform_during_shutdown));
}
// Create singleton.
if (s_AppDomainInfo == null)
{
s_AppDomainInfo = new AppDomainSetup();
s_AppDomainInfo.DisallowBindingRedirects = true;
s_AppDomainInfo.DisallowCodeDownload = true;
NamedPermissionSet perms = new NamedPermissionSet("__WebProxySandbox", PermissionState.None);
perms.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
ApplicationTrust trust = new ApplicationTrust();
trust.DefaultGrantSet = new PolicyStatement(perms);
s_AppDomainInfo.ApplicationTrust = trust;
s_AppDomainInfo.ApplicationBase = Environment.SystemDirectory;
}
// If something's already in s_ExcessAppDomain, try to dislodge it again.
AppDomain excessAppDomain = s_ExcessAppDomain;
if (excessAppDomain != null)
{
TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), excessAppDomain);
throw new InvalidOperationException(SR.GetString(SR.net_cant_create_environment));
}
appDomainIndex = s_NextAppDomainIndex++;
try { }
finally
{
PermissionSet permissionSet = new PermissionSet(PermissionState.None);
permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
//
s_ExcessAppDomain = AppDomain.CreateDomain(c_appDomainName, null, s_AppDomainInfo, permissionSet, null);
try
{
s_AppDomains.Add(appDomainIndex, s_ExcessAppDomain);
// This indicates to the finally and the finalizer that everything succeeded.
scriptDomain = s_ExcessAppDomain;
}
finally
{
// ReferenceEquals has a ReliabilityContract.
if (object.ReferenceEquals(scriptDomain, s_ExcessAppDomain))
{
s_ExcessAppDomain = null;
}
else
{
// Something failed. Leave the domain in s_ExcessAppDomain until we can get rid of it. No
// more AppDomains can be created until we do. In the mean time, keep attempting to get the
// TimerThread to remove it. Also, might as well remove it from the hash if it made it in.
try
{
s_AppDomains.Remove(appDomainIndex);
}
finally
{
// Can't call AppDomain.Unload from a user thread (or in a lock).
TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), s_ExcessAppDomain);
}
}
}
}
}
finally
{
if (lockHeld)
{
Monitor.Exit(s_AppDomains.SyncRoot);
}
}
}
internal void Close()
{
site.Close();
// Can't call AppDomain.Unload() from a user thread.
TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), appDomainIndex);
GC.SuppressFinalize(this);
}
// Bug 434828
//
// It's very hard to guarantee cleanup of an AppDomain. They aren't garbage collected, and Unload() is synchronous and
// can't be called from the finalizer thread. So we must have a finalizer that uses another thread, in this case the
// TimerThread, to unload the domain.
//
// 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
// clean it up properly. If the user wants to avoid the TimerThread being spun up for that purpose, they should save the
// existing DefaultWebProxy in a static before replacing it.
~AutoWebProxyScriptWrapper()
{
if (!NclUtilities.HasShutdownStarted && scriptDomain != null)
{
// Can't call AppDomain.Unload() from the finalizer thread.
TimerThread.GetOrCreateQueue(0).CreateTimer(new TimerThread.Callback(CloseAppDomainCallback), appDomainIndex);
}
}
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
private static void CloseAppDomainCallback(TimerThread.Timer timer, int timeNoticed, object context)
{
try
{
AppDomain domain = context as AppDomain;
if (domain == null)
{
CloseAppDomain((int) context);
}
else
{
if (object.ReferenceEquals(domain, s_ExcessAppDomain))
{
try
{
AppDomain.Unload(domain);
}
catch (AppDomainUnloadedException) { }
s_ExcessAppDomain = null;
}
}
}
catch (Exception exception)
{
if (NclUtilities.IsFatal(exception)) throw;
}
}
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
private static void CloseAppDomain(int index)
{
AppDomain appDomain;
// Locking s_AppDomains must happen in a CER so we don't orphan a lock that gets taken by AppDomain.DomainUnload.
bool lockHeld = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(s_AppDomains.SyncRoot, ref lockHeld);
if (s_CleanedUp)
{
return;
}
appDomain = (AppDomain) s_AppDomains[index];
}
finally
{
if (lockHeld)
{
Monitor.Exit(s_AppDomains.SyncRoot);
lockHeld = false;
}
}
try
{
// Cannot call Unload() in a lock shared by OnDomainUnload() - deadlock with ADUnload thread.
// So we may try to unload the same domain twice.
AppDomain.Unload(appDomain);
}
catch (AppDomainUnloadedException) { }
finally
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(s_AppDomains.SyncRoot, ref lockHeld);
s_AppDomains.Remove(index);
}
finally
{
if (lockHeld)
{
Monitor.Exit(s_AppDomains.SyncRoot);
}
}
}
}
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.MayFail)]
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlAppDomain)]
private static void OnDomainUnload(object sender, EventArgs e)
{
lock (s_AppDomains.SyncRoot)
{
if (!s_CleanedUp)
{
s_CleanedUp = true;
foreach (AppDomain domain in s_AppDomains.Values)
{
try
{
AppDomain.Unload(domain);
}
catch { }
}
s_AppDomains.Clear();
AppDomain excessAppDomain = s_ExcessAppDomain;
if (excessAppDomain != null)
{
try
{
AppDomain.Unload(excessAppDomain);
}
catch { }
s_ExcessAppDomain = null;
}
}
}
}
internal string ScriptBody
{
get
{
return scriptText;
}
}
internal byte[] Buffer
{
get
{
return scriptBytes;
}
set
{
scriptBytes = value;
}
}
internal DateTime LastModified
{
get
{
return lastModified;
}
set
{
lastModified = value;
}
}
private string scriptText;
private byte[] scriptBytes;
private DateTime lastModified;
// Forward these to the site.
internal string FindProxyForURL(string url, string host)
{
GlobalLog.Print("AutoWebProxyScriptWrapper::FindProxyForURL() Calling JScript for url:" + url.ToString() + " host:" + host.ToString());
return site.Run(url, host);
}
internal bool Compile(Uri engineScriptLocation, string scriptBody, byte[] buffer)
{
if (site.Load(engineScriptLocation, scriptBody, typeof(WebProxyScriptHelper)))
{
GlobalLog.Print("AutoWebProxyScriptWrapper::Compile() Compilation succeeded for engineScriptLocation:" + engineScriptLocation.ToString());
scriptText = scriptBody;
scriptBytes = buffer;
return true;
}
GlobalLog.Print("AutoWebProxyScriptWrapper::Compile() Compilation failed for engineScriptLocation:" + engineScriptLocation.ToString());
return false;
}
}
}
#endif
|