b61133a980a9b7703f1a428ec686b7a199bd1d55
[mono.git] / mcs / class / referencesource / System / net / System / Net / webproxy.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="webproxy.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net {
8     using System.Net.NetworkInformation;
9     using System.Globalization;
10     using System.Security.Permissions;
11     using System.Text;
12     using System.Text.RegularExpressions;
13     using System.Collections;
14     using System.Runtime.Serialization;
15     using System.Collections.Generic;
16     using System.Diagnostics.CodeAnalysis;
17
18     class WebProxyData {
19         internal bool bypassOnLocal;
20         internal bool automaticallyDetectSettings;
21         internal Uri proxyAddress;
22         internal Hashtable proxyHostAddresses;
23         internal Uri scriptLocation;
24 #if USE_WINIET_AUTODETECT_CACHE
25         internal Uri lkgScriptLocation;
26 #endif
27         internal ArrayList bypassList;
28     }
29
30     // Handles default proxy setting implementation for the Http proxy.
31     //
32     // The following order is used when determinig proxy settings:
33     // 1. web.config/app.config: if available, use settings specified in <system.net><defaultProxy>
34     // 2. If the config file doesn't contain proxy settings, read the IE proxy settings
35     //
36     // If the IE proxy settings contain invalid settings (e.g. "invalid;host" - note the semicolon), then
37     // a FormatException will be thrown.
38     [Serializable]
39     public class WebProxy : IAutoWebProxy, ISerializable {
40         // these are settable by the user
41         private bool _UseRegistry;    // This is just around for serialization. Can we get rid of it?
42         private bool _BypassOnLocal;
43         private bool m_EnableAutoproxy;
44         private Uri _ProxyAddress;
45         private ArrayList _BypassList;
46         private ICredentials _Credentials;
47
48         // these are computed on the fly
49         private Regex[] _RegExBypassList;
50         private Hashtable _ProxyHostAddresses;
51
52         /// <devdoc>
53         ///    <para>[To be supplied.]</para>
54         /// </devdoc>
55         public WebProxy()
56             : this((Uri) null, false, null, null) {
57         }
58
59         /// <devdoc>
60         ///    <para>[To be supplied.]</para>
61         /// </devdoc>
62         public WebProxy(Uri Address)
63             : this(Address, false, null, null) {
64         }
65
66         /// <devdoc>
67         ///    <para>[To be supplied.]</para>
68         /// </devdoc>
69         public WebProxy(Uri Address, bool BypassOnLocal)
70             : this(Address, BypassOnLocal, null, null) {
71         }
72
73         /// <devdoc>
74         ///    <para>[To be supplied.]</para>
75         /// </devdoc>
76         public WebProxy(Uri Address, bool BypassOnLocal, string[] BypassList)
77             : this(Address, BypassOnLocal, BypassList, null) {
78         }
79
80         /// <devdoc>
81         ///    <para>[To be supplied.]</para>
82         /// </devdoc>
83         public WebProxy(Uri Address, bool BypassOnLocal, string[] BypassList, ICredentials Credentials) {
84             _ProxyAddress = Address;
85             _BypassOnLocal = BypassOnLocal;
86             if (BypassList != null) {
87                 _BypassList = new ArrayList(BypassList);
88                 UpdateRegExList(true);
89             }
90             _Credentials = Credentials;
91             m_EnableAutoproxy = true;
92         }
93
94         /// <devdoc>
95         ///    <para>[To be supplied.]</para>
96         /// </devdoc>
97         public WebProxy(string Host, int Port)
98             : this(new Uri("http://" + Host + ":" + Port.ToString(CultureInfo.InvariantCulture)), false, null, null) {
99         }
100
101         /// <devdoc>
102         ///    <para>[To be supplied.]</para>
103         /// </devdoc>
104         public WebProxy(string Address)
105             : this(CreateProxyUri(Address), false, null, null) {
106         }
107
108         /// <devdoc>
109         ///    <para>[To be supplied.]</para>
110         /// </devdoc>
111         public WebProxy(string Address, bool BypassOnLocal)
112             : this(CreateProxyUri(Address), BypassOnLocal, null, null) {
113         }
114
115         /// <devdoc>
116         ///    <para>[To be supplied.]</para>
117         /// </devdoc>
118         public WebProxy(string Address, bool BypassOnLocal, string[] BypassList)
119             : this(CreateProxyUri(Address), BypassOnLocal, BypassList, null) {
120         }
121
122         /// <devdoc>
123         ///    <para>[To be supplied.]</para>
124         /// </devdoc>
125         public WebProxy(string Address, bool BypassOnLocal, string[] BypassList, ICredentials Credentials)
126             : this(CreateProxyUri(Address), BypassOnLocal, BypassList, Credentials) {
127         }
128
129         /// <devdoc>
130         ///    <para>[To be supplied.]</para>
131         /// </devdoc>
132         public Uri Address {
133             get {
134 #if !FEATURE_PAL
135                 CheckForChanges();
136 #endif // !FEATURE_PAL
137                return _ProxyAddress;
138             }
139             set {
140                 _UseRegistry = false;
141                 DeleteScriptEngine();
142                _ProxyHostAddresses = null;  // hash list of proxies
143                _ProxyAddress = value;
144             }
145         }
146
147         /// <devdoc>
148         ///    <para>[To be supplied.]</para>
149         /// </devdoc>
150         internal bool AutoDetect
151         {
152             set {
153                 GlobalLog.Assert(_UseRegistry == false, "Cannot set AutoDetect if we are using registry for proxy settings");
154                 GlobalLog.Assert(m_EnableAutoproxy, "WebProxy#{0}::.ctor()|Cannot set AutoDetect if usesystemdefault is set.", ValidationHelper.HashString(this));
155
156                 if (ScriptEngine == null)
157                 {
158                     ScriptEngine = new AutoWebProxyScriptEngine(this, false);
159                 }
160                 ScriptEngine.AutomaticallyDetectSettings = value;
161             }
162         }
163
164         /// <devdoc>
165         ///    <para>[To be supplied.]</para>
166         /// </devdoc>
167         internal Uri ScriptLocation {
168             set {
169                 GlobalLog.Assert(value != null, "Cannot set ScriptLocation to null");
170                 GlobalLog.Assert(_UseRegistry == false, "Cannot set AutoDetect if we are using registry for proxy settings");
171                 GlobalLog.Assert(m_EnableAutoproxy, "WebProxy#{0}::.ctor()|Cannot set ScriptLocation if usesystemdefault is set.", ValidationHelper.HashString(this));
172
173                 if (ScriptEngine == null)
174                 {
175                     ScriptEngine = new AutoWebProxyScriptEngine(this, false);
176                 }
177                 ScriptEngine.AutomaticConfigurationScript = value;
178             }
179         }
180
181         /// <devdoc>
182         ///    <para>[To be supplied.]</para>
183         /// </devdoc>
184         public bool BypassProxyOnLocal {
185             get {
186 #if !FEATURE_PAL
187                 CheckForChanges();
188 #endif // !FEATURE_PAL
189                 return _BypassOnLocal;
190             }
191             set {
192                 _UseRegistry = false;
193                 DeleteScriptEngine();
194                 _BypassOnLocal = value;
195             }
196         }
197
198         /// <devdoc>
199         ///    <para>[To be supplied.]</para>
200         /// </devdoc>
201         public string[] BypassList {
202             get {
203 #if !FEATURE_PAL
204                 CheckForChanges();
205 #endif // !FEATURE_PAL
206                 if (_BypassList == null) {
207                     _BypassList = new ArrayList();
208                 }
209                 return (string[])_BypassList.ToArray(typeof(string));
210             }
211             set {
212                 _UseRegistry = false;
213                 DeleteScriptEngine();
214                 _BypassList = new ArrayList(value);
215                 UpdateRegExList(true);
216             }
217         }
218
219         /// <devdoc>
220         ///    <para>[To be supplied.]</para>
221         /// </devdoc>
222         public ICredentials Credentials {
223             get {
224                 return _Credentials;
225             }
226             set {
227                 _Credentials = value;
228             }
229         }
230
231         /// <devdoc>
232         ///    <para>Sets Credentials to CredentialCache.DefaultCredentials</para>
233         /// </devdoc>
234         public bool UseDefaultCredentials  {
235             get {
236                 return (Credentials is SystemNetworkCredential) ? true : false;
237             }
238             set {
239                 _Credentials = value ? CredentialCache.DefaultCredentials : null;
240             }
241         }
242
243         /// <devdoc>
244         ///    <para>[To be supplied.]</para>
245         /// </devdoc>
246         public ArrayList BypassArrayList {
247             get {
248 #if !FEATURE_PAL
249                 CheckForChanges();
250 #endif // !FEATURE_PAL
251                 if ( _BypassList == null ) {
252                     _BypassList = new ArrayList();
253                 }
254                 return _BypassList;
255             }
256         }
257
258         internal void CheckForChanges() {
259             if (ScriptEngine != null)
260             {
261                 ScriptEngine.CheckForChanges();
262             }
263         }
264
265         /// <devdoc>
266         ///    <para>[To be supplied.]</para>
267         /// </devdoc>
268         public Uri GetProxy(Uri destination) {
269             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxy() destination:" + ValidationHelper.ToString(destination));
270             if (destination == null)
271             {
272                 throw new ArgumentNullException("destination");
273             }
274
275             Uri result;
276             if (GetProxyAuto(destination, out result)) {
277                 return result;
278             }
279             if (IsBypassedManual(destination)) {
280                 return destination;
281             }
282             Hashtable proxyHostAddresses = _ProxyHostAddresses;
283             Uri proxy = proxyHostAddresses!=null ? proxyHostAddresses[destination.Scheme] as Uri : _ProxyAddress;
284             return proxy!=null? proxy : destination;
285         }
286
287         //
288         // CreateProxyUri - maps string to Uri
289         //
290
291         private static Uri CreateProxyUri(string address) {
292             if (address == null) {
293                 return null;
294             }
295             if (address.IndexOf("://") == -1) {
296                 address = "http://" + address;
297             }
298             return new Uri(address);
299         }
300
301         //
302         // UpdateRegExList - Update internal _RegExBypassList
303         //  warning - can throw if the RegEx doesn't parse??
304         //
305         private void UpdateRegExList(bool canThrow) {
306             Regex[] regExBypassList = null;
307             ArrayList bypassList = _BypassList;
308             try {
309                 if ( bypassList != null && bypassList.Count > 0 ) {
310                     regExBypassList = new Regex[bypassList.Count];
311                     for (int i = 0; i < bypassList.Count; i++ ) {
312                         regExBypassList[i] = new Regex((string)bypassList[i], RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
313                     }
314                 }
315             }
316             catch {
317                 if (!canThrow) {
318                     _RegExBypassList = null;
319                     return;
320                 }
321                 throw;
322             }
323             // only update here, cause it could throw earlier in the loop
324             _RegExBypassList = regExBypassList;
325         }
326
327         //
328         // IsMatchInBypassList - match input against _RegExBypassList
329         //
330         private bool IsMatchInBypassList(Uri input) {
331             UpdateRegExList(false);
332             if ( _RegExBypassList == null ) {
333                 return false;
334             }
335             string matchUriString = input.Scheme + "://" + input.Host + (!input.IsDefaultPort ? (":"+input.Port) : "" );
336             for (int i = 0; i < _BypassList.Count; i++ ) {
337                 if (_RegExBypassList[i].IsMatch(matchUriString)) {
338                     return true;
339                 }
340             }
341             return false;
342         }
343
344         /// <devdoc>
345         /// Determines if the host Uri should be routed locally or go through the proxy.
346         /// </devdoc>
347         private bool IsLocal(Uri host) {
348             string hostString = host.Host;
349
350             IPAddress hostAddress;
351             if (IPAddress.TryParse(hostString, out hostAddress))
352             {
353                 return (IPAddress.IsLoopback(hostAddress) || NclUtilities.IsAddressLocal(hostAddress));
354             }
355             
356             int dot = hostString.IndexOf('.');
357
358             // No dot?  Local.
359             if (dot == -1)
360             {
361                 return true;
362             }
363             
364             // If it matches the primary domain, it's local.  (Whether or not the hostname matches.)
365             string local = "." + IPGlobalProperties.InternalGetIPGlobalProperties().DomainName;
366             if (local !=  null && local.Length == (hostString.Length - dot) &&
367                 string.Compare(local, 0, hostString, dot, local.Length, StringComparison.OrdinalIgnoreCase ) == 0) {
368                 return true;
369             }
370             return false;
371         }
372
373         /// <devdoc>
374         /// Determines if the host Uri should be routed locally or go through a proxy.
375         /// </devdoc>
376         private bool IsLocalInProxyHash(Uri host) {
377             Hashtable proxyHostAddresses = _ProxyHostAddresses;
378             if (proxyHostAddresses != null) {
379                 Uri proxy = (Uri) proxyHostAddresses[host.Scheme];
380                 if (proxy == null) {
381                     return true; // no proxy entry for this scheme, then bypass
382                 }
383             }
384             return false;
385         }
386
387
388         /// <devdoc>
389         ///    <para>[To be supplied.]</para>
390         /// </devdoc>
391         public bool IsBypassed(Uri host) {
392             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::IsBypassed() destination:" + ValidationHelper.ToString(host));
393             if (host == null)
394             {
395                 throw new ArgumentNullException("host");
396             }
397
398             bool result; 
399             if (IsBypassedAuto(host, out result)) {
400                 return result;
401             }
402             return IsBypassedManual(host);
403         }
404
405         private bool IsBypassedManual(Uri host) {
406             if (host.IsLoopback) {
407                 return true; // bypass localhost from using a proxy.
408             }
409             return (_ProxyAddress==null && _ProxyHostAddresses==null) || (_BypassOnLocal && IsLocal(host)) || IsMatchInBypassList(host) || IsLocalInProxyHash(host);
410         }
411
412         /// <devdoc>
413         ///    <para>[To be supplied.]</para>
414         /// </devdoc>
415         [Obsolete("This method has been deprecated. Please use the proxy selected for you by default. http://go.microsoft.com/fwlink/?linkid=14202")]
416         public static WebProxy GetDefaultProxy() {
417 #if FEATURE_MONO_CAS
418             ExceptionHelper.WebPermissionUnrestricted.Demand();
419 #endif
420             return new WebProxy(true);
421         }
422
423         //
424         // ISerializable constructor
425         //
426         /// <devdoc>
427         ///    <para>[To be supplied.]</para>
428         /// </devdoc>
429         protected WebProxy(SerializationInfo serializationInfo, StreamingContext streamingContext) {
430             // first check for useRegistry on the serialized proxy
431             bool useRegistry = false;
432             try {
433                 useRegistry = serializationInfo.GetBoolean("_UseRegistry");
434             }
435             catch {
436             }
437             if (useRegistry) {
438                 // just make the proxy advanced, don't populate with any settings
439                 // note - this will happen in the context of the user performing the deserialization (their proxy settings get read)
440 #if FEATURE_MONO_CAS
441                 ExceptionHelper.WebPermissionUnrestricted.Demand();
442 #endif
443                 UnsafeUpdateFromRegistry();
444                 return;
445             }
446             // normal proxy
447             _ProxyAddress   = (Uri)serializationInfo.GetValue("_ProxyAddress", typeof(Uri));
448             _BypassOnLocal  = serializationInfo.GetBoolean("_BypassOnLocal");
449             _BypassList     = (ArrayList)serializationInfo.GetValue("_BypassList", typeof(ArrayList));
450             try {
451                 UseDefaultCredentials = serializationInfo.GetBoolean("_UseDefaultCredentials");
452             }
453             catch {
454             }
455         }
456
457         //
458         // ISerializable method
459         //
460         /// <internalonly/>
461         /// <devdoc>
462         ///    <para>[To be supplied.]</para>
463         /// </devdoc>
464         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
465         [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)]
466         void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
467         {
468             GetObjectData(serializationInfo, streamingContext);
469         }
470
471         //
472         // FxCop: provide a way for derived classes to access this method even if they reimplement ISerializable.
473         //
474         [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
475         protected virtual void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
476         {
477             serializationInfo.AddValue("_BypassOnLocal", _BypassOnLocal);
478             serializationInfo.AddValue("_ProxyAddress", _ProxyAddress);
479             serializationInfo.AddValue("_BypassList", _BypassList);
480             serializationInfo.AddValue("_UseDefaultCredentials", UseDefaultCredentials);
481             if (_UseRegistry) {
482                 serializationInfo.AddValue("_UseRegistry", true);
483             }
484         }
485
486
487         /// <summary>
488         ///     Handles proxy settings by using Internet Explorer based settings,
489         ///     keep in mind the security implications when downloading and running
490         ///     script from any network source configured in Internet Explorer.
491         /// </summary>
492
493         private AutoWebProxyScriptEngine m_ScriptEngine;
494
495         internal AutoWebProxyScriptEngine ScriptEngine {
496             get {
497                 return m_ScriptEngine;
498             }
499             set {
500                 m_ScriptEngine = value;
501             }
502         }
503
504 #if MONO
505         public static IWebProxy CreateDefaultProxy ()
506         {
507 #if MONOTOUCH_WATCH
508             throw new PlatformNotSupportedException ();
509 #elif MONOTOUCH
510             return Mono.Net.CFNetwork.GetDefaultProxy ();
511 #elif MONODROID
512             // Return the system web proxy.  This only works for ICS+.
513             var data = AndroidPlatform.GetDefaultProxy ();
514             if (data != null)
515                 return data;
516 #else
517             if (Platform.IsMacOS) {
518                 var data = Mono.Net.CFNetwork.GetDefaultProxy ();
519                 if (data != null)
520                     return data;
521             }
522 #endif
523
524             return new WebProxy (true);
525         }
526 #endif
527
528         // This constructor is used internally to make WebProxies that read their state from the registry.
529         // 
530         internal WebProxy(bool enableAutoproxy)
531         {
532             m_EnableAutoproxy = enableAutoproxy;
533             UnsafeUpdateFromRegistry();
534         }
535
536         internal void DeleteScriptEngine() {
537             if (ScriptEngine != null) {
538                 ScriptEngine.Close();
539                 ScriptEngine = null;
540             }
541         }
542
543         internal void UnsafeUpdateFromRegistry() {
544             GlobalLog.Assert(!_UseRegistry, "WebProxy#{0}::UnsafeUpdateFromRegistry()|_UseRegistry ScriptEngine#{1}", ValidationHelper.HashString(this), ValidationHelper.HashString(m_ScriptEngine));
545             _UseRegistry = true;
546 #if !FEATURE_PAL || !MOBILE
547             ScriptEngine = new AutoWebProxyScriptEngine(this, true);
548             WebProxyData webProxyData = ScriptEngine.GetWebProxyData();
549
550             Update(webProxyData);
551 #endif
552         }
553
554         internal void Update(WebProxyData webProxyData) {
555 #if TRAVE
556             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::Update() Before " + DumpIWebProxy(this));
557 #endif
558             // update needs to happen atomically
559             lock (this) {
560                 _BypassOnLocal = webProxyData.bypassOnLocal;
561                 _ProxyAddress = webProxyData.proxyAddress;
562                 _ProxyHostAddresses = webProxyData.proxyHostAddresses;
563                 _BypassList = webProxyData.bypassList;
564
565                 ScriptEngine.AutomaticallyDetectSettings = m_EnableAutoproxy && webProxyData.automaticallyDetectSettings;
566                 ScriptEngine.AutomaticConfigurationScript = m_EnableAutoproxy ? webProxyData.scriptLocation : null;
567             }
568 #if TRAVE
569             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::Update() After " + DumpIWebProxy(this));
570 #endif
571         }
572
573         /// <devdoc>
574         /// <para>
575         /// We really didn't want to expose this. IWebProxy is kind of broken so we needed
576         /// a different way of calling into IsBypassed/GetProxy with a single method call.
577         /// We need to make it public though, so it is. This API will return null if
578         /// the proxy is to be bypassed, otherwise it returns an array of Uri to proxise
579         /// that may be used to access the destination. If an entry in the array is null
580         /// we want to try a direct access. Today we only attempt using the first entry.
581         /// </para>
582         /// </devdoc>
583         ProxyChain IAutoWebProxy.GetProxies(Uri destination) {
584             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxies() destination:" + ValidationHelper.ToString(destination));
585             if (destination == null)
586             {
587                 throw new ArgumentNullException("destination");
588             }
589             return new ProxyScriptChain(this, destination);
590         }
591
592 #if TRAVE
593         internal static string DumpIWebProxy(IWebProxy proxy) {
594             StringBuilder stringBuilder = new StringBuilder();
595             stringBuilder.Append(" Type: " + ValidationHelper.ToString(proxy.GetType()) + "\r\n");
596             WebProxy webProxy = proxy as WebProxy;
597             if (webProxy!=null) {
598                 stringBuilder.Append(" - Address: " + ValidationHelper.ToString(webProxy._ProxyAddress) + "\r\n");
599                 stringBuilder.Append(" - BypassProxyOnLocal: " + ValidationHelper.ToString(webProxy._BypassOnLocal) + "\r\n");
600             }
601             stringBuilder.Append(" - -------------------------------------------------");
602             return stringBuilder.ToString();
603         }
604 #endif
605
606         //
607         // IWebProxy implementation
608         //
609
610         // Get proxies can never return null in the case of ExecutionSuccess.
611         private bool GetProxyAuto(Uri destination, out Uri proxyUri) {
612             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxyAuto() destination:" + ValidationHelper.ToString(destination));
613             
614             proxyUri = null;
615             if (ScriptEngine == null) {
616                 return false;
617             }
618             IList<string> proxies = null;
619             if (!ScriptEngine.GetProxies(destination, out proxies)) {
620                 return false;
621             }
622
623             // Returning null in case 'proxies.Count == 0' means, no proxy available (incl. DIRECT), the request is prohibited.
624             if (proxies.Count > 0) {
625                 if (AreAllBypassed(proxies, true)) {
626                     // this is the broken behaviour of IWebProxy. Returning the same destination means bypass
627                     proxyUri = destination;
628                 }
629                 else {
630                     proxyUri = ProxyUri(proxies[0]);
631                 }
632             }
633             return true;
634         }
635
636         private bool IsBypassedAuto(Uri destination, out bool isBypassed) {
637             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::IsBypassedAuto() destination:" + ValidationHelper.ToString(destination));
638
639             isBypassed = true;
640
641             if (ScriptEngine == null) {
642                 return false;
643             }
644             IList<string> proxyList; 
645             if (!ScriptEngine.GetProxies(destination, out proxyList)) {
646                 return false;
647             }
648             if (proxyList.Count == 0) {
649                 isBypassed = false;
650             }
651             else {
652                 isBypassed = AreAllBypassed(proxyList, true);
653             }
654             return true;
655         }
656
657         internal Uri[] GetProxiesAuto(Uri destination, ref int syncStatus)
658         {
659             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxiesAuto() destination:" + ValidationHelper.ToString(destination));
660
661             if (ScriptEngine == null) {
662                 return null;
663             }
664
665             IList<string> proxyList = null;           
666             if (!ScriptEngine.GetProxies(destination, out proxyList, ref syncStatus)) {
667                 return null;
668             }
669
670             Uri[] proxyUris = null;
671             if (proxyList.Count == 0) {
672                 proxyUris = new Uri[] { };
673             }
674             else if (AreAllBypassed(proxyList, false)) {
675                 proxyUris = new Uri[] { null };
676             }
677             else {
678                 proxyUris = new Uri[proxyList.Count];
679                 for (int i = 0; i < proxyList.Count; i++) {
680                     proxyUris[i] = ProxyUri(proxyList[i]);
681                 }
682             }
683             return proxyUris;
684         }
685
686         internal void AbortGetProxiesAuto(ref int syncStatus)
687         {
688             if (ScriptEngine != null)
689             {
690                 ScriptEngine.Abort(ref syncStatus);
691             }
692         }
693
694         internal Uri GetProxyAutoFailover(Uri destination)
695         {
696             if (IsBypassedManual(destination))
697             {
698                 return null;
699             }
700
701             Uri proxy = _ProxyAddress;
702             Hashtable proxyHostAddresses = _ProxyHostAddresses;
703             if (proxyHostAddresses != null)
704             {
705                 proxy = proxyHostAddresses[destination.Scheme] as Uri;
706             }
707             return proxy;
708         }
709
710         private static bool AreAllBypassed(IEnumerable<string> proxies, bool checkFirstOnly) {
711             bool isBypassed = true;
712
713             foreach (string proxy in proxies) {
714                 isBypassed = string.IsNullOrEmpty(proxy);
715                 
716                 if (checkFirstOnly || !isBypassed) {
717                     break;
718                 }
719             }
720
721             return isBypassed;
722         }
723
724         private static Uri ProxyUri(string proxyName) {
725             return proxyName==null || proxyName.Length==0 ? null : new Uri("http://" + proxyName);
726         }
727     }
728 }