Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System / net / System / Net / Configuration / DefaultProxySection.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DefaultProxySection.cs" company="Microsoft Corporation">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net.Configuration
8 {
9     using System.Collections.Generic;
10     using System.Configuration;
11     using System.Globalization;
12     using System.Net;
13     using System.Reflection;
14     using System.Threading;
15     using System.Security;
16     using System.Security.Permissions;
17     using System.Security.Principal;
18     using System.ComponentModel;
19
20 #if !MONO
21     public sealed class DefaultProxySection : ConfigurationSection
22     {
23         public DefaultProxySection()
24         {
25             this.properties.Add(this.bypasslist);
26             this.properties.Add(this.module);
27             this.properties.Add(this.proxy);
28             this.properties.Add(this.enabled);
29             this.properties.Add(this.useDefaultCredentials);
30         }
31
32         protected override void PostDeserialize()
33         {
34             // Perf optimization. If the configuration is coming from machine.config
35             // It is safe and we don't need to check for permissions.
36             if (EvaluationContext.IsMachineLevel)
37                 return;
38
39             try {
40                 ExceptionHelper.WebPermissionUnrestricted.Demand();
41             } catch (Exception exception) {
42                 throw new ConfigurationErrorsException(
43                               SR.GetString(SR.net_config_section_permission, 
44                                            ConfigurationStrings.DefaultProxySectionName),
45                               exception);
46             }
47         }
48          
49         [ConfigurationProperty(ConfigurationStrings.BypassList)]
50         public BypassElementCollection BypassList
51         {
52             get { return (BypassElementCollection)this[this.bypasslist]; }
53         }
54
55         [ConfigurationProperty(ConfigurationStrings.Module)]
56         public ModuleElement Module
57         {
58             get { return (ModuleElement)this[this.module]; }
59         }
60
61         protected override ConfigurationPropertyCollection Properties
62         {
63             get { return this.properties; }
64         }
65         
66         [ConfigurationProperty(ConfigurationStrings.Proxy)]
67         public ProxyElement Proxy
68         {
69             get { return (ProxyElement)this[this.proxy]; }
70         }
71
72         [ConfigurationProperty(ConfigurationStrings.Enabled, DefaultValue = true)]
73         public bool Enabled
74         {
75             get { return (bool) this[this.enabled]; }
76             set { this[this.enabled] = value; }
77         }
78
79         [ConfigurationProperty(ConfigurationStrings.UseDefaultCredentials, DefaultValue = false)]
80         public bool UseDefaultCredentials
81         {
82             get { return (bool) this[this.useDefaultCredentials]; }
83             set { this[this.useDefaultCredentials] = value; }
84         }
85
86         ConfigurationPropertyCollection properties = new ConfigurationPropertyCollection();
87
88         readonly ConfigurationProperty bypasslist =
89             new ConfigurationProperty(ConfigurationStrings.BypassList, 
90                                       typeof(BypassElementCollection), 
91                                       null,
92                                       ConfigurationPropertyOptions.None);
93
94         readonly ConfigurationProperty module =
95             new ConfigurationProperty(ConfigurationStrings.Module, 
96                                       typeof(ModuleElement), 
97                                       null,
98                                       ConfigurationPropertyOptions.None);
99
100         readonly ConfigurationProperty proxy =
101             new ConfigurationProperty(ConfigurationStrings.Proxy, 
102                                       typeof(ProxyElement), 
103                                       null,
104                                       ConfigurationPropertyOptions.None);
105
106         readonly ConfigurationProperty enabled =
107             new ConfigurationProperty(ConfigurationStrings.Enabled, 
108                                       typeof(bool), 
109                                       true, 
110                                       ConfigurationPropertyOptions.None);
111
112         readonly ConfigurationProperty useDefaultCredentials =
113             new ConfigurationProperty(ConfigurationStrings.UseDefaultCredentials, 
114                                       typeof(bool), 
115                                       false,
116                                       ConfigurationPropertyOptions.None);
117
118
119         // This allows us to prevent parent settings (machine.config) from propegating to higher config (app.config), unless
120         // the higher config doesn't contain the section at all.  That is, overriding defaultProxy is all-or-nothing.
121         // Template from Microsoft.
122         protected override void Reset(ConfigurationElement parentElement)
123         {
124             // Ignore the parentElement parameter by changing it to the default settings
125             DefaultProxySection defaultElement = new DefaultProxySection();
126
127             // Initialize the parentElement to the right set of defaults (not needed now,
128             // but this will avoid errors in the future if SetDefaults is ever overridden in this class.
129             // ConfigurationElement::InitializeDefault is a no-op, so you aren\92t hurting perf by anything
130             // measurable. 
131             defaultElement.InitializeDefault();
132
133             // Finally, pass it to the base class to do the \93right things\94
134             base.Reset(defaultElement);
135         }
136     }
137 #endif
138     internal sealed class DefaultProxySectionInternal
139     {
140 #if !MONO
141         [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
142         internal DefaultProxySectionInternal(DefaultProxySection section)
143         {
144             // If enabled is false, skip everything.
145             if (!section.Enabled)
146             {
147                 return;
148             }
149
150             // If nothing else is set, use the system default.
151             if (section.Proxy.AutoDetect == ProxyElement.AutoDetectValues.Unspecified &&
152                 section.Proxy.ScriptLocation == null &&
153                 String.IsNullOrEmpty(section.Module.Type) &&
154                 section.Proxy.UseSystemDefault != ProxyElement.UseSystemDefaultValues.True &&
155                 section.Proxy.ProxyAddress == null &&
156                 section.Proxy.BypassOnLocal == ProxyElement.BypassOnLocalValues.Unspecified &&
157                 section.BypassList.Count == 0)
158             {
159                 // Old-style indication to turn off the proxy.
160                 if (section.Proxy.UseSystemDefault == ProxyElement.UseSystemDefaultValues.False)
161                 {
162                     this.webProxy = new EmptyWebProxy();
163
164                     // Intentionally ignoring UseDefaultCredentials in this case.
165                     return;
166                 }
167
168                 // Suspend impersonation.
169                 try {
170                     new SecurityPermission(SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode).Assert();
171 #if !FEATURE_PAL
172                     using(WindowsIdentity.Impersonate(IntPtr.Zero))
173 #endif // !FEATURE_PAL
174                     {
175                         CodeAccessPermission.RevertAssert();
176                         this.webProxy = new WebRequest.WebProxyWrapper(new WebProxy(true));
177                     }
178                 } catch {
179                     throw;
180                 }
181             }
182             else
183             {
184                 // First, check out if we are using a different module type
185                 if (!String.IsNullOrEmpty(section.Module.Type))
186                 {
187                     Type theType = Type.GetType(section.Module.Type, true, true);
188                     
189                     if ((theType.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public)
190                         throw new ConfigurationErrorsException(SR.GetString(SR.net_config_proxy_module_not_public));
191                     
192                     // verify that its of the proper type of IWebProxy
193                     if (!typeof(IWebProxy).IsAssignableFrom(theType))
194                     {
195                         throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
196                                                                     theType.FullName,
197                                                                     "IWebProxy"));
198                     }
199                     this.webProxy = (IWebProxy)Activator.CreateInstance(
200                                     theType,
201                                     BindingFlags.CreateInstance
202                                     | BindingFlags.Instance
203                                     | BindingFlags.NonPublic
204                                     | BindingFlags.Public,
205                                     null,          // Binder
206                                     new object[0], // no arguments
207                                     CultureInfo.InvariantCulture
208                                     );
209                 }
210                 else if (section.Proxy.UseSystemDefault == ProxyElement.UseSystemDefaultValues.True &&
211                          section.Proxy.AutoDetect == ProxyElement.AutoDetectValues.Unspecified &&
212                          section.Proxy.ScriptLocation == null)
213                 {
214                     // Suspend impersonation.  This setting is deprecated but required for Everett compat.
215                     try {
216                         new SecurityPermission(SecurityPermissionFlag.ControlPrincipal | SecurityPermissionFlag.UnmanagedCode).Assert();
217 #if !FEATURE_PAL
218                         using(WindowsIdentity.Impersonate(IntPtr.Zero))
219 #endif // !FEATURE_PAL
220                         {
221                             CodeAccessPermission.RevertAssert();
222                             this.webProxy = new WebProxy(false);
223                         }
224                     } catch {
225                         throw;
226                     }
227                 }
228                 else
229                 {
230                     this.webProxy = new WebProxy();
231                 }
232
233                 WebProxy tempProxy = this.webProxy as WebProxy;
234
235                 if (tempProxy != null)
236                 {
237                     if (section.Proxy.AutoDetect != ProxyElement.AutoDetectValues.Unspecified)
238                     {
239                         tempProxy.AutoDetect = section.Proxy.AutoDetect == ProxyElement.AutoDetectValues.True;
240                     }
241                     if (section.Proxy.ScriptLocation != null)
242                     {
243                         tempProxy.ScriptLocation = section.Proxy.ScriptLocation;
244                     }
245                     if (section.Proxy.BypassOnLocal != ProxyElement.BypassOnLocalValues.Unspecified)
246                     {
247                         tempProxy.BypassProxyOnLocal = section.Proxy.BypassOnLocal == ProxyElement.BypassOnLocalValues.True;
248                     }
249                     if (section.Proxy.ProxyAddress != null)
250                     {
251                         tempProxy.Address = section.Proxy.ProxyAddress;
252                     }
253                     int bypassListSize = section.BypassList.Count;
254                     if (bypassListSize > 0)
255                     {
256                         string[] bypassList = new string[section.BypassList.Count];
257                         for (int index = 0; index < bypassListSize; ++index)
258                         {
259                             bypassList[index] = section.BypassList[index].Address;
260                         }
261                         tempProxy.BypassList = bypassList;
262                     }
263
264                     // Wrap it if type not explicitly specified in Module.
265                     if (section.Module.Type == null)
266                     {
267                         this.webProxy = new WebRequest.WebProxyWrapper(tempProxy);
268                     }
269                 }
270             }
271
272             // Now apply UseDefaultCredentials if there's a proxy.
273             if (this.webProxy != null && section.UseDefaultCredentials)
274             {
275                 this.webProxy.Credentials = SystemNetworkCredential.defaultCredential;
276             }
277         }
278 #else
279
280         static IWebProxy GetDefaultProxy_UsingOldMonoCode()
281         {
282 #if CONFIGURATION_DEP
283             DefaultProxySection sec = ConfigurationManager.GetSection ("system.net/defaultProxy") as DefaultProxySection;
284             WebProxy p;
285             
286             if (sec == null)
287                 return GetSystemWebProxy ();
288             
289             ProxyElement pe = sec.Proxy;
290             
291             if ((pe.UseSystemDefault != ProxyElement.UseSystemDefaultValues.False) && (pe.ProxyAddress == null)) {
292                 IWebProxy proxy = GetSystemWebProxy ();
293                 
294                 if (!(proxy is WebProxy))
295                     return proxy;
296                 
297                 p = (WebProxy) proxy;
298             } else
299                 p = new WebProxy ();
300             
301             if (pe.ProxyAddress != null)
302                 p.Address = pe.ProxyAddress;
303             
304             if (pe.BypassOnLocal != ProxyElement.BypassOnLocalValues.Unspecified)
305                 p.BypassProxyOnLocal = (pe.BypassOnLocal == ProxyElement.BypassOnLocalValues.True);
306                 
307             foreach(BypassElement elem in sec.BypassList)
308                 p.BypassArrayList.Add(elem.Address);
309             
310             return p;
311 #else
312             return GetSystemWebProxy ();
313 #endif
314         }
315
316         static IWebProxy GetSystemWebProxy()
317         {
318             return System.Net.WebProxy.CreateDefaultProxy ();
319         }
320
321 #endif
322
323         internal static object ClassSyncObject
324         {
325             get
326             {
327                 if (classSyncObject == null)
328                 {
329                     object o = new object();
330                     Interlocked.CompareExchange(ref classSyncObject, o, null);
331                 }
332                 return classSyncObject;
333             }
334         }
335
336         static internal DefaultProxySectionInternal GetSection()
337         {
338             lock (DefaultProxySectionInternal.ClassSyncObject)
339             {
340 #if MONO
341                 var res = new DefaultProxySectionInternal();
342                 res.webProxy = GetDefaultProxy_UsingOldMonoCode ();
343                 return res;
344 #else
345                 DefaultProxySection section = PrivilegedConfigurationManager.GetSection(ConfigurationStrings.DefaultProxySectionPath) as DefaultProxySection;
346                 if (section == null)
347                     return null;
348
349                 try
350                 {
351                     return new DefaultProxySectionInternal(section);
352                 }
353                 catch (Exception exception)
354                 {
355                     if (NclUtilities.IsFatal(exception)) throw;
356
357                     throw new ConfigurationErrorsException(SR.GetString(SR.net_config_proxy), exception);
358                 }
359 #endif
360             }
361         }
362
363         internal IWebProxy WebProxy
364         {
365             get { return this.webProxy; }
366         }
367
368         private IWebProxy webProxy;
369         private static object classSyncObject;
370     }
371 }