We need you! We're working hard on the next version of Developer Fusion - Let us know what you think we should be up to!

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. <