Implement mono_gc_alloc_fixed on Boehm to be uncollectable. This matches SGen behavio...
[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 FEATURE_NO_BSD_SOCKETS
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
517             return new WebProxy (true);
518 #else
519             if (Platform.IsMacOS) {
520                 var data = Mono.Net.CFNetwork.GetDefaultProxy ();
521                 if (data != null)
522                     return data;
523             }
524
525             return new WebProxy (true);
526 #endif
527         }
528 #endif
529
530         // This constructor is used internally to make WebProxies that read their state from the registry.
531         // 
532         internal WebProxy(bool enableAutoproxy)
533         {
534             m_EnableAutoproxy = enableAutoproxy;
535             UnsafeUpdateFromRegistry();
536         }
537
538         internal void DeleteScriptEngine() {
539             if (ScriptEngine != null) {
540                 ScriptEngine.Close();
541                 ScriptEngine = null;
542             }
543         }
544
545         internal void UnsafeUpdateFromRegistry() {
546             GlobalLog.Assert(!_UseRegistry, "WebProxy#{0}::UnsafeUpdateFromRegistry()|_UseRegistry ScriptEngine#{1}", ValidationHelper.HashString(this), ValidationHelper.HashString(m_ScriptEngine));
547             _UseRegistry = true;
548 #if !FEATURE_PAL || !MOBILE
549             ScriptEngine = new AutoWebProxyScriptEngine(this, true);
550             WebProxyData webProxyData = ScriptEngine.GetWebProxyData();
551
552             Update(webProxyData);
553 #endif
554         }
555
556         internal void Update(WebProxyData webProxyData) {
557 #if TRAVE
558             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::Update() Before " + DumpIWebProxy(this));
559 #endif
560             // update needs to happen atomically
561             lock (this) {
562                 _BypassOnLocal = webProxyData.bypassOnLocal;
563                 _ProxyAddress = webProxyData.proxyAddress;
564                 _ProxyHostAddresses = webProxyData.proxyHostAddresses;
565                 _BypassList = webProxyData.bypassList;
566
567                 ScriptEngine.AutomaticallyDetectSettings = m_EnableAutoproxy && webProxyData.automaticallyDetectSettings;
568                 ScriptEngine.AutomaticConfigurationScript = m_EnableAutoproxy ? webProxyData.scriptLocation : null;
569             }
570 #if TRAVE
571             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::Update() After " + DumpIWebProxy(this));
572 #endif
573         }
574
575         /// <devdoc>
576         /// <para>
577         /// We really didn't want to expose this. IWebProxy is kind of broken so we needed
578         /// a different way of calling into IsBypassed/GetProxy with a single method call.
579         /// We need to make it public though, so it is. This API will return null if
580         /// the proxy is to be bypassed, otherwise it returns an array of Uri to proxise
581         /// that may be used to access the destination. If an entry in the array is null
582         /// we want to try a direct access. Today we only attempt using the first entry.
583         /// </para>
584         /// </devdoc>
585         ProxyChain IAutoWebProxy.GetProxies(Uri destination) {
586             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxies() destination:" + ValidationHelper.ToString(destination));
587             if (destination == null)
588             {
589                 throw new ArgumentNullException("destination");
590             }
591             return new ProxyScriptChain(this, destination);
592         }
593
594 #if TRAVE
595         internal static string DumpIWebProxy(IWebProxy proxy) {
596             StringBuilder stringBuilder = new StringBuilder();
597             stringBuilder.Append(" Type: " + ValidationHelper.ToString(proxy.GetType()) + "\r\n");
598             WebProxy webProxy = proxy as WebProxy;
599             if (webProxy!=null) {
600                 stringBuilder.Append(" - Address: " + ValidationHelper.ToString(webProxy._ProxyAddress) + "\r\n");
601                 stringBuilder.Append(" - BypassProxyOnLocal: " + ValidationHelper.ToString(webProxy._BypassOnLocal) + "\r\n");
602             }
603             stringBuilder.Append(" - -------------------------------------------------");
604             return stringBuilder.ToString();
605         }
606 #endif
607
608         //
609         // IWebProxy implementation
610         //
611
612         // Get proxies can never return null in the case of ExecutionSuccess.
613         private bool GetProxyAuto(Uri destination, out Uri proxyUri) {
614             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxyAuto() destination:" + ValidationHelper.ToString(destination));
615             
616             proxyUri = null;
617             if (ScriptEngine == null) {
618                 return false;
619             }
620             IList<string> proxies = null;
621             if (!ScriptEngine.GetProxies(destination, out proxies)) {
622                 return false;
623             }
624
625             // Returning null in case 'proxies.Count == 0' means, no proxy available (incl. DIRECT), the request is prohibited.
626             if (proxies.Count > 0) {
627                 if (AreAllBypassed(proxies, true)) {
628                     // this is the broken behaviour of IWebProxy. Returning the same destination means bypass
629                     proxyUri = destination;
630                 }
631                 else {
632                     proxyUri = ProxyUri(proxies[0]);
633                 }
634             }
635             return true;
636         }
637
638         private bool IsBypassedAuto(Uri destination, out bool isBypassed) {
639             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::IsBypassedAuto() destination:" + ValidationHelper.ToString(destination));
640
641             isBypassed = true;
642
643             if (ScriptEngine == null) {
644                 return false;
645             }
646             IList<string> proxyList; 
647             if (!ScriptEngine.GetProxies(destination, out proxyList)) {
648                 return false;
649             }
650             if (proxyList.Count == 0) {
651                 isBypassed = false;
652             }
653             else {
654                 isBypassed = AreAllBypassed(proxyList, true);
655             }
656             return true;
657         }
658
659         internal Uri[] GetProxiesAuto(Uri destination, ref int syncStatus)
660         {
661             GlobalLog.Print("WebProxy#" + ValidationHelper.HashString(this) + "::GetProxiesAuto() destination:" + ValidationHelper.ToString(destination));
662
663             if (ScriptEngine == null) {
664                 return null;
665             }
666
667             IList<string> proxyList = null;           
668             if (!ScriptEngine.GetProxies(destination, out proxyList, ref syncStatus)) {
669                 return null;
670             }
671
672             Uri[] proxyUris = null;
673             if (proxyList.Count == 0) {
674                 proxyUris = new Uri[] { };
675             }
676             else if (AreAllBypassed(proxyList, false)) {
677                 proxyUris = new Uri[] { null };
678             }
679             else {
680                 proxyUris = new Uri[proxyList.Count];
681                 for (int i = 0; i < proxyList.Count; i++) {
682                     proxyUris[i] = ProxyUri(proxyList[i]);
683                 }
684             }
685             return proxyUris;
686         }
687
688         internal void AbortGetProxiesAuto(ref int syncStatus)
689         {
690             if (ScriptEngine != null)
691             {
692                 ScriptEngine.Abort(ref syncStatus);
693             }
694         }
695
696         internal Uri GetProxyAutoFailover(Uri destination)
697         {
698             if (IsBypassedManual(destination))
699             {
700                 return null;
701             }
702
703             Uri proxy = _ProxyAddress;
704             Hashtable proxyHostAddresses = _ProxyHostAddresses;
705             if (proxyHostAddresses != null)
706             {
707                 proxy = proxyHostAddresses[destination.Scheme] as Uri;
708             }
709             return proxy;
710         }
711
712         private static bool AreAllBypassed(IEnumerable<string> proxies, bool checkFirstOnly) {
713             bool isBypassed = true;
714
715             foreach (string proxy in proxies) {
716                 isBypassed = string.IsNullOrEmpty(proxy);
717                 
718                 if (checkFirstOnly || !isBypassed) {
719                     break;
720                 }
721             }
722
723             return isBypassed;
724         }
725
726         private static Uri ProxyUri(string proxyName) {
727             return proxyName==null || proxyName.Length==0 ? null : new Uri("http://" + proxyName);
728         }
729     }
730 }