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

  1. //------------------------------------------------------------------------------
  2. // <copyright fieldInfole="_AutoWebProxyScriptEngine.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. namespace System.Net
  16. {
  17.     using System.IO;
  18.     using System.Collections;
  19.     using System.Collections.Specialized;
  20.     using System.Threading;
  21.     using System.Text;
  22.     using System.Net.Cache;
  23.     using System.Globalization;
  24.     using System.Net.Configuration;
  25.     using System.Security.Permissions;
  26.    
  27.     enum AutoWebProxyState
  28.     {
  29.         Uninitialized = 0,
  30.         DiscoveryFailure = 1,
  31.         DiscoverySuccess = 2,
  32.         DownloadFailure = 3,
  33.         DownloadSuccess = 4,
  34.         CompilationFailure = 5,
  35.         CompilationSuccess = 6,
  36.         ExecutionFailure = 7,
  37.         ExecutionSuccess = 8
  38.     }
  39.    
  40.     /// <summary>
  41.     /// Simple EXE host for the AutoWebProxyScriptEngine. Pushes the contents of a script file
  42.     /// into the engine and executes it. Exposes the JScript model used in IE 3.2 - 6,
  43.     /// for resolving which proxy to use.
  44.     /// </summary>
  45.     internal class AutoWebProxyScriptEngine
  46.     {
  47.         private static readonly char[] splitChars = new char[] {';'};
  48.        
  49.         private static TimerThread.Queue s_TimerQueue;
  50.         private static readonly TimerThread.Callback s_TimerCallback = new TimerThread.Callback(RequestTimeoutCallback);
  51.         private static readonly WaitCallback s_AbortWrapper = new WaitCallback(AbortWrapper);
  52.        
  53.         private bool automaticallyDetectSettings;
  54.         private Uri automaticConfigurationScript;
  55.        
  56.         private AutoWebProxyScriptWrapper scriptInstance;
  57.         internal AutoWebProxyState state;
  58.         private Uri engineScriptLocation;
  59.         private WebProxy webProxy;
  60.        
  61.         private RequestCache backupCache;
  62.        
  63.         // Used by abortable lock.
  64.         private bool m_LockHeld;
  65.         private WebRequest m_LockedRequest;
  66.        
  67.         private bool m_UseRegistry;
  68.        
  69.        
  70.         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
  71.         internal AutoWebProxyScriptEngine(WebProxy proxy, bool useRegistry)
  72.         {
  73.             webProxy = proxy;
  74.             m_UseRegistry = useRegistry;
  75.            
  76.             backupCache = new SingleItemRequestCache(RequestCacheManager.IsCachingEnabled);
  77.         }
  78.        
  79.        
  80.         // AutoWebProxyScriptEngine has special abortable locking. No one should ever lock (this) except the locking helper methods below.
  81.         private static class SyncStatus
  82.         {
  83.             internal const int Unlocked = 0;
  84.             internal const int Locking = 1;
  85.             internal const int LockOwner = 2;
  86.             internal const int RequestOwner = 3;
  87.             internal const int AbortedLocked = 4;
  88.             internal const int Aborted = 5;
  89.         }
  90.        
  91.         private void EnterLock(ref int syncStatus)
  92.         {
  93.             if (syncStatus == SyncStatus.Unlocked) {
  94.                 lock (this) {
  95.                     if (syncStatus != SyncStatus.Aborted) {
  96.                         syncStatus = SyncStatus.Locking;
  97.                         while (true) {
  98.                             if (!m_LockHeld) {
  99.                                 syncStatus = SyncStatus.LockOwner;
  100.                                 m_LockHeld = true;
  101.                                 return;
  102.                             }
  103.                             Monitor.Wait(this);
  104.                             if (syncStatus == SyncStatus.Aborted) {
  105.                                 Monitor.Pulse(this);
  106.                                 // This is to ensure that a Pulse meant to let someone take the lock isn't lost.
  107.                                 return;
  108.                             }
  109.                         }
  110.                     }
  111.                 }
  112.             }
  113.         }
  114.        
  115.         private void ExitLock(ref int syncStatus)
  116.         {
  117.             if (syncStatus != SyncStatus.Unlocked && syncStatus != SyncStatus.Aborted) {
  118.                 lock (this) {
  119.                     if (syncStatus == SyncStatus.RequestOwner) {
  120.                         m_LockedRequest = null;
  121.                     }
  122.                     m_LockHeld = false;
  123.                     if (syncStatus == SyncStatus.AbortedLocked) {
  124.                         state = AutoWebProxyState.Uninitialized;
  125.                         syncStatus = SyncStatus.Aborted;
  126.                     }
  127.                     else {
  128.                         syncStatus = SyncStatus.Unlocked;
  129.                     }
  130.                     Monitor.Pulse(this);
  131.                 }
  132.             }
  133.         }
  134.        
  135.         private void LockRequest(WebRequest request, ref int syncStatus)
  136.         {
  137.             lock (this) {
  138.                 switch (syncStatus) {
  139.                     case SyncStatus.LockOwner:
  140.                         m_LockedRequest = request;
  141.                         syncStatus = SyncStatus.RequestOwner;
  142.                         break;
  143.                     case SyncStatus.RequestOwner:
  144.                        
  145.                         m_LockedRequest = request;
  146.                         break;
  147.                 }
  148.             }
  149.         }
  150.        
  151.         internal void Abort(ref int syncStatus)
  152.         {
  153.             lock (this) {
  154.                 switch (syncStatus) {
  155.                     case SyncStatus.Unlocked:
  156.                         syncStatus = SyncStatus.Aborted;
  157.                         break;
  158.                     case SyncStatus.Locking:
  159.                        
  160.                         syncStatus = SyncStatus.Aborted;
  161.                         Monitor.PulseAll(this);
  162.                         break;
  163.                     case SyncStatus.LockOwner:
  164.                        
  165.                         syncStatus = SyncStatus.AbortedLocked;
  166.                         break;
  167.                     case SyncStatus.RequestOwner:
  168.                        
  169.                         ThreadPool.UnsafeQueueUserWorkItem(s_AbortWrapper, m_LockedRequest);
  170.                         syncStatus = SyncStatus.AbortedLocked;
  171.                         m_LockedRequest = null;
  172.                         break;
  173.                 }
  174.             }
  175.         }
  176.         // End of locking helper methods.
  177.        
  178.        
  179.        
  180.         // The lock is always held while these three are modified.
  181.         internal bool AutomaticallyDetectSettings {
  182.             set {
  183.                 if (automaticallyDetectSettings != value) {
  184.                     state = AutoWebProxyState.Uninitialized;
  185.                     automaticallyDetectSettings = value;
  186.                 }
  187.             }
  188.         }
  189.        
  190.         internal Uri AutomaticConfigurationScript {
  191.             set {
  192.                 if (!object.Equals(automaticConfigurationScript, value)) {
  193.                     automaticConfigurationScript = value;
  194.                    
  195.                     {
  196.                         state = AutoWebProxyState.Uninitialized;
  197.                     }
  198.                 }
  199.             }
  200.         }
  201.        
  202.        
  203.         // from wininet.h
  204.         //
  205.         // #define INTERNET_MAX_PATH_LENGTH 2048
  206.         // #define INTERNET_MAX_PROTOCOL_NAME "gopher" // longest protocol name
  207.         // #define INTERNET_MAX_URL_LENGTH ((sizeof(INTERNET_MAX_PROTOCOL_NAME) - 1) \
  208.         // + sizeof("://") \
  209.         // + INTERNET_MAX_PATH_LENGTH)
  210.         //
  211.         private const int MaximumProxyStringLength = 2058;
  212.        
  213.         /// <devdoc>
  214.         /// <para>
  215.         /// Called to discover script location. This performs
  216.         /// autodetection using the method specified in the detectFlags.
  217.         /// </para>
  218.         /// </devdoc>
  219.         unsafe private static Uri SafeDetectAutoProxyUrl(uint discoveryMethod)
  220.         {
  221.             Uri autoProxy = null;
  222.            
  223.            
  224.             return autoProxy;
  225.         }
  226.        
  227.         internal StringCollection GetProxies(Uri destination, bool returnFirstOnly, out AutoWebProxyState autoWebProxyState)
  228.         {
  229.             int syncStatus = SyncStatus.Unlocked;
  230.             return GetProxies(destination, returnFirstOnly, out autoWebProxyState, ref syncStatus);
  231.         }
  232.        
  233.         internal StringCollection GetProxies(Uri destination, bool returnFirstOnly, out AutoWebProxyState autoWebProxyState, ref int syncStatus)
  234.         {
  235.             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies() state:" + ValidationHelper.ToString(state));
  236.            
  237.            
  238.             if (state == AutoWebProxyState.DiscoveryFailure) {
  239.                 // No engine will be available anyway, shortcut the call.
  240.                 autoWebProxyState = state;
  241.                 return null;
  242.             }
  243.            
  244.             // This whole thing has to be locked, both to prevent simultaneous downloading / compilation, and
  245.             // because the script isn't threadsafe.
  246.             string scriptReturn = null;
  247.             try {
  248.                 EnterLock(ref syncStatus);
  249.                 if (syncStatus != SyncStatus.LockOwner) {
  250.                     // This is typically because a download got aborted.
  251.                     autoWebProxyState = AutoWebProxyState.DownloadFailure;
  252.                     return null;
  253.                 }
  254.                
  255.                 autoWebProxyState = EnsureEngineAvailable(ref syncStatus);
  256.                 if (autoWebProxyState != AutoWebProxyState.CompilationSuccess) {
  257.                     // the script can't run, say we're not ready and bypass
  258.                     return null;
  259.                 }
  260.                 autoWebProxyState = AutoWebProxyState.ExecutionFailure;
  261.                 try {
  262.                     scriptReturn = scriptInstance.FindProxyForURL(destination.ToString(), destination.Host);
  263.                     autoWebProxyState = AutoWebProxyState.ExecutionSuccess;
  264.                     GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies() calling ExecuteFindProxyForURL() for destination:" + ValidationHelper.ToString(destination) + " returned scriptReturn:" + ValidationHelper.ToString(scriptReturn));
  265.                 }
  266.                 catch (Exception exception) {
  267.                     if (NclUtilities.IsFatal(exception))
  268.                         throw;
  269.                     if (Logging.On)
  270.                         Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_script_execution_error, exception));
  271.                     GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies() calling ExecuteFindProxyForURL() for destination:" + ValidationHelper.ToString(destination) + " threw:" + ValidationHelper.ToString(exception));
  272.                 }
  273.             }
  274.             finally {
  275.                 ExitLock(ref syncStatus);
  276.             }
  277.            
  278.             if (autoWebProxyState == AutoWebProxyState.ExecutionFailure) {
  279.                 // the script failed at runtime, say we're not ready and bypass
  280.                 return null;
  281.             }
  282.             StringCollection proxies = ParseScriptReturn(scriptReturn, destination, returnFirstOnly);
  283.             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies() proxies:" + ValidationHelper.ToString(proxies));
  284.             return proxies;
  285.         }
  286.        
  287.         /// <devdoc>
  288.         /// <para>
  289.         /// Ensures that (if state is AutoWebProxyState.CompilationSuccess) there is an engine available to execute script.
  290.         /// Figures out the script location (might discover if needed).
  291.         /// Calls DownloadAndCompile().
  292.         /// </para>
  293.         /// </devdoc>
  294.         private AutoWebProxyState EnsureEngineAvailable(ref int syncStatus)
  295.         {
  296.             GlobalLog.Enter("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable");
  297.             AutoWebProxyScriptWrapper newScriptInstance;
  298.            
  299.             if (state == AutoWebProxyState.Uninitialized || engineScriptLocation == null) {
  300.                
  301.                 // Either Auto-Detect wasn't enabled or something failed with it. Try the manual script location.
  302.                 if (automaticConfigurationScript != null) {
  303.                     GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable() using automaticConfigurationScript:" + ValidationHelper.ToString(automaticConfigurationScript) + " engineScriptLocation:" + ValidationHelper.ToString(engineScriptLocation));
  304.                     state = AutoWebProxyState.DiscoverySuccess;
  305.                     if (automaticConfigurationScript.Equals(engineScriptLocation)) {
  306.                         state = AutoWebProxyState.CompilationSuccess;
  307.                         GlobalLog.Leave("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable", ValidationHelper.ToString(state));
  308.                         return state;
  309.                     }
  310.                     state = DownloadAndCompile(automaticConfigurationScript, out newScriptInstance, ref syncStatus);
  311.                     if (state == AutoWebProxyState.CompilationSuccess) {
  312.                         UpdateScriptInstance(newScriptInstance);
  313.                         engineScriptLocation = automaticConfigurationScript;
  314.                         GlobalLog.Leave("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable", ValidationHelper.ToString(state));
  315.                         return state;
  316.                     }
  317.                 }
  318.             }
  319.             else {
  320.                 // We always want to call DownloadAndCompile to check the expiration.
  321.                 GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable() state:" + state + " engineScriptLocation:" + ValidationHelper.ToString(engineScriptLocation));
  322.                 state = AutoWebProxyState.DiscoverySuccess;
  323.                 state = DownloadAndCompile(engineScriptLocation, out newScriptInstance, ref syncStatus);
  324.                 if (state == AutoWebProxyState.CompilationSuccess) {
  325.                     UpdateScriptInstance(newScriptInstance);
  326.                     GlobalLog.Leave("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable", ValidationHelper.ToString(state));
  327.                     return state;
  328.                 }
  329.                
  330.                 // There's still an opportunity to fail over to the automaticConfigurationScript.
  331.                 if (!engineScriptLocation.Equals(automaticConfigurationScript)) {
  332.                     GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable() Update failed. Falling back to automaticConfigurationScript:" + ValidationHelper.ToString(automaticConfigurationScript));
  333.                     state = AutoWebProxyState.DiscoverySuccess;
  334.                     state = DownloadAndCompile(automaticConfigurationScript, out newScriptInstance, ref syncStatus);
  335.                     if (state == AutoWebProxyState.CompilationSuccess) {
  336.                         UpdateScriptInstance(newScriptInstance);
  337.                         engineScriptLocation = automaticConfigurationScript;
  338.                         GlobalLog.Leave("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable", ValidationHelper.ToString(state));
  339.                         return state;
  340.                     }
  341.                 }
  342.             }
  343.            
  344.             // Everything failed. Set this instance to mostly-dead. It will wake up again if there's a reg/connectoid change.
  345.             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable() All failed.");
  346.             state = AutoWebProxyState.DiscoveryFailure;
  347.             UpdateScriptInstance(null);
  348.             engineScriptLocation = null;
  349.            
  350.             GlobalLog.Leave("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::EnsureEngineAvailable", ValidationHelper.ToString(state));
  351.             return state;
  352.         }
  353.        
  354.         void UpdateScriptInstance(AutoWebProxyScriptWrapper newScriptInstance)
  355.         {
  356.             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::UpdateScriptInstance() updating scriptInstance#" + ValidationHelper.HashString(scriptInstance) + " to newScriptInstance#" + ValidationHelper.HashString(newScriptInstance));
  357.            
  358.             if (scriptInstance == newScriptInstance) {
  359.                 return;
  360.             }
  361.            
  362.             if (scriptInstance != null) {
  363.                 GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::UpdateScriptInstance() Closing engine.");
  364.                 scriptInstance.Close();
  365.             }
  366.             scriptInstance = newScriptInstance;
  367.         }
  368.        
  369.         /// <devdoc>
  370.         /// <para>
  371.         /// Downloads and compiles the script from a given Uri.
  372.         /// This code can be called by config for a downloaded control, we need to assert.
  373.         /// This code is called holding the lock.
  374.         /// </para>
  375.         /// </devdoc>
  376.         private AutoWebProxyState DownloadAndCompile(Uri location, out AutoWebProxyScriptWrapper newScriptInstance, ref int syncStatus)
  377.         {
  378.             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() location:" + ValidationHelper.ToString(location));
  379.             AutoWebProxyState newState = AutoWebProxyState.DownloadFailure;
  380.             WebResponse response = null;
  381.             TimerThread.Timer timer = null;
  382.             newScriptInstance = null;
  383.            
  384.             // Can't assert this in declarative form (DCR?). This Assert() is needed to be able to create the request to download the proxy script.
  385.             ExceptionHelper.WebPermissionUnrestricted.Assert();
  386.             try {
  387.                 // here we have a reentrance issue due to config load.
  388.                 WebRequest request = WebRequest.Create(location);
  389.                 request.Timeout = Timeout.Infinite;
  390.                 request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default);
  391.                 request.ConnectionGroupName = "__WebProxyScript";
  392.                
  393.                 // We have an opportunity here, if caching is disabled AppDomain-wide, to override it with a
  394.                 // custom, trivial cache-provider to get a similar semantic.
  395.                 //
  396.                 // We also want to have a backup caching key in the case when IE has locked an expired script response
  397.                 //
  398.                 if (request.CacheProtocol != null) {
  399.                     GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Using backup caching.");
  400.                     request.CacheProtocol = new RequestCacheProtocol(backupCache, request.CacheProtocol.Validator);
  401.                 }
  402.                
  403.                 HttpWebRequest httpWebRequest = request as HttpWebRequest;
  404.                 if (httpWebRequest != null) {
  405.                     httpWebRequest.Accept = "*/*";
  406.                     httpWebRequest.UserAgent = this.GetType().FullName + "/" + Environment.Version;
  407.                     httpWebRequest.KeepAlive = false;
  408.                     httpWebRequest.Pipelined = false;
  409.                     httpWebRequest.InternalConnectionGroup = true;
  410.                 }
  411.                 else {
  412.                     FtpWebRequest ftpWebRequest = request as FtpWebRequest;
  413.                     if (ftpWebRequest != null) {
  414.                         ftpWebRequest.KeepAlive = false;
  415.                     }
  416.                 }
  417.                
  418.                 // Use no proxy, default cache - initiate the download.
  419.                 request.Proxy = null;
  420.                 request.Credentials = webProxy.Credentials;
  421.                
  422.                 // Set this up with the abortable lock to abort this too.
  423.                 LockRequest(request, ref syncStatus);
  424.                 if (syncStatus != SyncStatus.RequestOwner) {
  425.                     throw new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
  426.                 }
  427.                
  428.                 // Use our own timeout timer so that it can encompass the whole request, not just the headers.
  429.                 if (s_TimerQueue == null) {
  430.                     s_TimerQueue = TimerThread.GetOrCreateQueue(SettingsSectionInternal.Section.DownloadTimeout);
  431.                 }
  432.                 timer = s_TimerQueue.CreateTimer(s_TimerCallback, request);
  433.                 response = request.GetResponse();
  434.                
  435.                 // Check Last Modified.
  436.                 DateTime lastModified = DateTime.MinValue;
  437.                 HttpWebResponse httpResponse = response as HttpWebResponse;
  438.                 if (httpResponse != null) {
  439.                     lastModified = httpResponse.LastModified;
  440.                 }
  441.                 else {
  442.                     FtpWebResponse ftpResponse = response as FtpWebResponse;
  443.                     if (ftpResponse != null) {
  444.                         lastModified = ftpResponse.LastModified;
  445.                     }
  446.                 }
  447.                 GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() lastModified:" + lastModified.ToString() + " (script):" + (scriptInstance == null ? "(null)" : scriptInstance.LastModified.ToString()));
  448.                 if (scriptInstance != null && lastModified != DateTime.MinValue && scriptInstance.LastModified == lastModified) {
  449.                     newScriptInstance = scriptInstance;
  450.                     newState = AutoWebProxyState.CompilationSuccess;
  451.                 }
  452.                 else {
  453.                     string scriptBody = null;
  454.                     byte[] scriptBuffer = null;
  455.                     using (Stream responseStream = response.GetResponseStream()) {
  456.                         SingleItemRequestCache.ReadOnlyStream ros = responseStream as SingleItemRequestCache.ReadOnlyStream;
  457.                         if (ros != null) {
  458.                             scriptBuffer = ros.Buffer;
  459.                         }
  460.                         if (scriptInstance != null && scriptBuffer != null && scriptBuffer == scriptInstance.Buffer) {
  461.                             scriptInstance.LastModified = lastModified;
  462.                             newScriptInstance = scriptInstance;
  463.                             newState = AutoWebProxyState.CompilationSuccess;
  464.                             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Buffer matched - reusing engine.");
  465.                         }
  466.                         else {
  467.                             using (StreamReader streamReader = new StreamReader(responseStream)) {
  468.                                 scriptBody = streamReader.ReadToEnd();
  469.                             }
  470.                         }
  471.                     }
  472.                    
  473.                     WebResponse tempResponse = response;
  474.                     response = null;
  475.                     tempResponse.Close();
  476.                     timer.Cancel();
  477.                     timer = null;
  478.                    
  479.                     if (newState != AutoWebProxyState.CompilationSuccess) {
  480.                         newState = AutoWebProxyState.DownloadSuccess;
  481.                        
  482.                         GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() IsFromCache:" + tempResponse.IsFromCache.ToString() + " scriptInstance:" + ValidationHelper.HashString(scriptInstance));
  483.                         if (scriptInstance != null && scriptBody == scriptInstance.ScriptBody) {
  484.                             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Script matched - using existing engine.");
  485.                             scriptInstance.LastModified = lastModified;
  486.                             if (scriptBuffer != null) {
  487.                                 scriptInstance.Buffer = scriptBuffer;
  488.                             }
  489.                             newScriptInstance = scriptInstance;
  490.                             newState = AutoWebProxyState.CompilationSuccess;
  491.                         }
  492.                         else {
  493.                             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Creating AutoWebProxyScriptWrapper.");
  494.                             newScriptInstance = new AutoWebProxyScriptWrapper();
  495.                             newScriptInstance.LastModified = lastModified;
  496.                             newState = newScriptInstance.Compile(location, scriptBody, scriptBuffer);
  497.                         }
  498.                     }
  499.                 }
  500.             }
  501.             catch (Exception exception) {
  502.                 if (NclUtilities.IsFatal(exception))
  503.                     throw;
  504.                 if (Logging.On)
  505.                     Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_script_download_compile_error, exception));
  506.                 GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() Download() threw:" + ValidationHelper.ToString(exception));
  507.             }
  508.             finally {
  509.                 if (timer != null) {
  510.                     timer.Cancel();
  511.                 }
  512.                
  513.                 //
  514.                 try {
  515.                     if (response != null) {
  516.                         response.Close();
  517.                     }
  518.                 }
  519.                 finally {
  520.                     WebPermission.RevertAssert();
  521.                 }
  522.             }
  523.             if (newState != AutoWebProxyState.CompilationSuccess) {
  524.                 newScriptInstance = null;
  525.             }
  526.             GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::DownloadAndCompile() retuning newState:" + ValidationHelper.ToString(newState));
  527.             return newState;
  528.         }
  529.        
  530.         // RequestTimeoutCallback - Called by the TimerThread to abort a request. This just posts ThreadPool work item - Abort() does too
  531.         // much to be done on the timer thread (timer thread should never block or call user code).
  532.         private static void RequestTimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
  533.         {
  534.             ThreadPool.UnsafeQueueUserWorkItem(s_AbortWrapper, context);
  535.         }
  536.        
  537.         private static void AbortWrapper(object context)
  538.         {
  539.             #if DEBUG
  540.             GlobalLog.SetThreadSource(ThreadKinds.Worker);
  541.             using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
  542.                 #endif
  543.                 ((WebRequest)context).Abort();
  544.                 #if DEBUG
  545.             }
  546.             #endif
  547.         }
  548.        
  549.         private StringCollection ParseScriptReturn(string scriptReturn, Uri destination, bool returnFirstOnly)
  550.         {
  551.             if (scriptReturn == null) {
  552.                 return new StringCollection();
  553.             }
  554.             StringCollection proxies = new StringCollection();
  555.             string[] proxyListStrings = scriptReturn.Split(splitChars);
  556.             string proxyAuthority;
  557.             foreach (string s in proxyListStrings) {
  558.                 string proxyString = s.Trim(' ');
  559.                 if (!proxyString.StartsWith("PROXY ", StringComparison.InvariantCultureIgnoreCase)) {
  560.                     if (string.Compare("DIRECT", proxyString, StringComparison.InvariantCultureIgnoreCase) == 0) {
  561.                         proxyAuthority = null;
  562.                     }
  563.                     else {
  564.                         continue;
  565.                     }
  566.                 }
  567.                 else {
  568.                     proxyAuthority = proxyString.Substring(6).TrimStart(' ');
  569.                     Uri uri = null;
  570.                     bool tryParse = Uri.TryCreate("http://" + proxyAuthority, UriKind.Absolute, out uri);
  571.                     if (!tryParse || uri.UserInfo.Length > 0 || uri.HostNameType == UriHostNameType.Basic || uri.AbsolutePath.Length != 1 || proxyAuthority[proxyAuthority.Length - 1] == '/' || proxyAuthority[proxyAuthority.Length - 1] == '#' || proxyAuthority[proxyAuthority.Length - 1] == '?') {
  572.                         continue;
  573.                     }
  574.                 }
  575.                 proxies.Add(proxyAuthority);
  576.                 if (returnFirstOnly) {
  577.                     break;
  578.                 }
  579.             }
  580.             return proxies;
  581.         }
  582.        
  583.         internal void Close()
  584.         {
  585.         }
  586.        
  587.        
  588.     }
  589. }

Developer Fusion