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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="_ProxyChain.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.Collections;
  18.     using System.Collections.Generic;
  19.    
  20.     internal interface IAutoWebProxy : IWebProxy
  21.     {
  22.         ProxyChain GetProxies(Uri destination);
  23.     }
  24.    
  25.     internal abstract class ProxyChain : IEnumerable<Uri>, IDisposable
  26.     {
  27.         private List<Uri> m_Cache = new List<Uri>();
  28.         private bool m_CacheComplete;
  29.         private ProxyEnumerator m_MainEnumerator;
  30.         private Uri m_Destination;
  31.         private HttpAbortDelegate m_HttpAbortDelegate;
  32.        
  33.         protected ProxyChain(Uri destination)
  34.         {
  35.             m_Destination = destination;
  36.         }
  37.        
  38.         public IEnumerator<Uri> GetEnumerator()
  39.         {
  40.             ProxyEnumerator enumerator = new ProxyEnumerator(this);
  41.             if (m_MainEnumerator == null) {
  42.                 m_MainEnumerator = enumerator;
  43.             }
  44.             return enumerator;
  45.         }
  46.        
  47.         IEnumerator IEnumerable.GetEnumerator()
  48.         {
  49.             return GetEnumerator();
  50.         }
  51.        
  52.         public virtual void Dispose()
  53.         {
  54.         }
  55.        
  56.         internal IEnumerator<Uri> Enumerator {
  57.             get { return m_MainEnumerator == null ? GetEnumerator() : m_MainEnumerator; }
  58.         }
  59.        
  60.         internal Uri Destination {
  61.             get { return m_Destination; }
  62.         }
  63.        
  64.         // MoveNext can be time-consuming (download proxy script). This lets you abort it.
  65.         internal virtual void Abort()
  66.         {
  67.         }
  68.        
  69.         internal bool HttpAbort(HttpWebRequest request, WebException webException)
  70.         {
  71.             Abort();
  72.             return true;
  73.         }
  74.        
  75.         internal HttpAbortDelegate HttpAbortDelegate {
  76.             get {
  77.                 if (m_HttpAbortDelegate == null) {
  78.                     m_HttpAbortDelegate = new HttpAbortDelegate(HttpAbort);
  79.                 }
  80.                 return m_HttpAbortDelegate;
  81.             }
  82.         }
  83.        
  84.         protected abstract bool GetNextProxy(out Uri proxy);
  85.        
  86.         // This implementation prevents DIRECT (null) from being returned more than once.
  87.         private class ProxyEnumerator : IEnumerator<Uri>
  88.         {
  89.             private ProxyChain m_Chain;
  90.             private bool m_Finished;
  91.             private int m_CurrentIndex = -1;
  92.             private bool m_TriedDirect;
  93.            
  94.             internal ProxyEnumerator(ProxyChain chain)
  95.             {
  96.                 m_Chain = chain;
  97.             }
  98.            
  99.             public Uri Current {
  100.                 get {
  101.                     if (m_Finished || m_CurrentIndex < 0) {
  102.                         throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
  103.                     }
  104.                    
  105.                     GlobalLog.Assert(m_Chain.m_Cache.Count > m_CurrentIndex, "ProxyEnumerator::Current|Not all proxies made it to the cache.");
  106.                     return m_Chain.m_Cache[m_CurrentIndex];
  107.                 }
  108.             }
  109.            
  110.             object IEnumerator.Current {
  111.                 get { return Current; }
  112.             }
  113.            
  114.             public bool MoveNext()
  115.             {
  116.                 if (m_Finished) {
  117.                     return false;
  118.                 }
  119.                
  120.                 checked {
  121.                     m_CurrentIndex++;
  122.                 }
  123.                 if (m_Chain.m_Cache.Count > m_CurrentIndex) {
  124.                     return true;
  125.                 }
  126.                
  127.                 if (m_Chain.m_CacheComplete) {
  128.                     m_Finished = true;
  129.                     return false;
  130.                 }
  131.                
  132.                 lock (m_Chain.m_Cache) {
  133.                     if (m_Chain.m_Cache.Count > m_CurrentIndex) {
  134.                         return true;
  135.                     }
  136.                    
  137.                     if (m_Chain.m_CacheComplete) {
  138.                         m_Finished = true;
  139.                         return false;
  140.                     }
  141.                    
  142.                     Uri nextProxy;
  143.                     while (true) {
  144.                         if (!m_Chain.GetNextProxy(out nextProxy)) {
  145.                             m_Finished = true;
  146.                             m_Chain.m_CacheComplete = true;
  147.                             return false;
  148.                         }
  149.                        
  150.                         if (nextProxy == null) {
  151.                             if (m_TriedDirect) {
  152.                                 continue;
  153.                             }
  154.                             m_TriedDirect = true;
  155.                         }
  156.                         break;
  157.                     }
  158.                    
  159.                     m_Chain.m_Cache.Add(nextProxy);
  160.                     GlobalLog.Assert(m_Chain.m_Cache.Count > m_CurrentIndex, "ProxyEnumerator::MoveNext|Not all proxies made it to the cache.");
  161.                     return true;
  162.                 }
  163.             }
  164.            
  165.             public void Reset()
  166.             {
  167.                 m_Finished = false;
  168.                 m_CurrentIndex = -1;
  169.             }
  170.            
  171.             public void Dispose()
  172.             {
  173.             }
  174.         }
  175.     }
  176.    
  177.    
  178.     // This class implements failover logic for proxy scripts.
  179.     internal class ProxyScriptChain : ProxyChain
  180.     {
  181.         private WebProxy m_Proxy;
  182.         private Uri[] m_ScriptProxies;
  183.         private int m_CurrentIndex;
  184.         private int m_SyncStatus;
  185.        
  186.         internal ProxyScriptChain(WebProxy proxy, Uri destination) : base(destination)
  187.         {
  188.             m_Proxy = proxy;
  189.         }
  190.        
  191.         protected override bool GetNextProxy(out Uri proxy)
  192.         {
  193.             if (m_CurrentIndex < 0) {
  194.                 proxy = null;
  195.                 return false;
  196.             }
  197.            
  198.             if (m_CurrentIndex == 0) {
  199.                 AutoWebProxyState state;
  200.                 m_ScriptProxies = m_Proxy.GetProxiesAuto(Destination, out state, ref m_SyncStatus);
  201.                 if (state != AutoWebProxyState.ExecutionSuccess) {
  202.                     m_ScriptProxies = null;
  203.                 }
  204.             }
  205.            
  206.             if (m_ScriptProxies == null || m_CurrentIndex >= m_ScriptProxies.Length) {
  207.                 proxy = m_Proxy.GetProxyAutoFailover(Destination);
  208.                 m_CurrentIndex = -1;
  209.                 return true;
  210.             }
  211.            
  212.             proxy = m_ScriptProxies[m_CurrentIndex++];
  213.             return true;
  214.         }
  215.        
  216.         internal override void Abort()
  217.         {
  218.             m_Proxy.AbortGetProxiesAuto(ref m_SyncStatus);
  219.         }
  220.     }
  221.    
  222.     // This class says to use no proxy.
  223.     internal class DirectProxy : ProxyChain
  224.     {
  225.         private bool m_ProxyRetrieved;
  226.        
  227.         internal DirectProxy(Uri destination) : base(destination)
  228.         {
  229.         }
  230.        
  231.         protected override bool GetNextProxy(out Uri proxy)
  232.         {
  233.             proxy = null;
  234.             if (m_ProxyRetrieved) {
  235.                 return false;
  236.             }
  237.             m_ProxyRetrieved = true;
  238.             return true;
  239.         }
  240.     }
  241.    
  242.     // This class says to use a single fixed proxy.
  243.     internal class StaticProxy : ProxyChain
  244.     {
  245.         private Uri m_Proxy;
  246.        
  247.         internal StaticProxy(Uri destination, Uri proxy) : base(destination)
  248.         {
  249.             if (proxy == null) {
  250.                 throw new ArgumentNullException("proxy");
  251.             }
  252.             m_Proxy = proxy;
  253.         }
  254.        
  255.         protected override bool GetNextProxy(out Uri proxy)
  256.         {
  257.             proxy = m_Proxy;
  258.             if (proxy == null) {
  259.                 return false;
  260.             }
  261.             m_Proxy = null;
  262.             return true;
  263.         }
  264.     }
  265. }

Developer Fusion