2 // System.Net.WebRequest
5 // Lawrence Pit (loz@cable.a2000.nl)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2011 Xamarin Inc.
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Configuration;
35 using System.Reflection;
36 using System.Runtime.Serialization;
37 using System.Globalization;
38 using System.Net.Configuration;
39 using System.Net.Security;
40 using System.Net.Cache;
41 using System.Security.Principal;
42 using System.Threading.Tasks;
43 using System.Text.RegularExpressions;
47 using ConfigurationException = System.ArgumentException;
49 namespace System.Net.Configuration {
57 public abstract class WebRequest : MarshalByRefObject, ISerializable {
58 static HybridDictionary prefixes = new HybridDictionary ();
59 static bool isDefaultWebProxySet;
60 static IWebProxy defaultWebProxy;
61 static RequestCachePolicy defaultCachePolicy;
63 internal const int DefaultTimeout = 100000;
68 IWebRequestCreate http = new HttpRequestCreator ();
69 RegisterPrefix ("http", http);
70 RegisterPrefix ("https", http);
71 RegisterPrefix ("file", new FileWebRequestCreator ());
72 RegisterPrefix ("ftp", new FtpRequestCreator ());
75 object cfg = ConfigurationManager.GetSection ("system.net/webRequestModules");
76 WebRequestModulesSection s = cfg as WebRequestModulesSection;
78 foreach (WebRequestModuleElement el in
80 AddPrefix (el.Prefix, el.Type);
84 ConfigurationSettings.GetConfig ("system.net/webRequestModules");
88 protected WebRequest ()
92 protected WebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext)
96 static Exception GetMustImplement ()
98 return new NotImplementedException ("This method must be implemented in derived classes");
103 private AuthenticationLevel authentication_level = AuthenticationLevel.MutualAuthRequested;
105 public AuthenticationLevel AuthenticationLevel
108 return(authentication_level);
111 authentication_level = value;
115 public virtual string ConnectionGroupName {
116 get { throw GetMustImplement (); }
117 set { throw GetMustImplement (); }
120 public virtual long ContentLength {
121 get { throw GetMustImplement (); }
122 set { throw GetMustImplement (); }
125 public virtual string ContentType {
126 get { throw GetMustImplement (); }
127 set { throw GetMustImplement (); }
130 public virtual ICredentials Credentials {
131 get { throw GetMustImplement (); }
132 set { throw GetMustImplement (); }
135 [MonoTODO ("Implement the caching system. Currently always returns a policy with the NoCacheNoStore level")]
136 public virtual RequestCachePolicy CachePolicy
138 get { return DefaultCachePolicy; }
143 public static RequestCachePolicy DefaultCachePolicy {
145 return defaultCachePolicy ?? (defaultCachePolicy = new HttpRequestCachePolicy (HttpRequestCacheLevel.NoCacheNoStore));
148 throw GetMustImplement ();
152 public virtual WebHeaderCollection Headers {
153 get { throw GetMustImplement (); }
154 set { throw GetMustImplement (); }
158 public virtual string Method {
159 get { throw GetMustImplement (); }
160 set { throw GetMustImplement (); }
163 public virtual bool PreAuthenticate {
164 get { throw GetMustImplement (); }
165 set { throw GetMustImplement (); }
168 public virtual IWebProxy Proxy {
169 get { throw GetMustImplement (); }
170 set { throw GetMustImplement (); }
173 public virtual Uri RequestUri {
174 get { throw GetMustImplement (); }
177 public virtual int Timeout {
178 get { throw GetMustImplement (); }
179 set { throw GetMustImplement (); }
182 public virtual bool UseDefaultCredentials
185 throw GetMustImplement ();
188 throw GetMustImplement ();
192 public TokenImpersonationLevel ImpersonationLevel { get; set; }
194 // volatile static IWebProxy proxy;
195 static readonly object lockobj = new object ();
197 public static IWebProxy DefaultWebProxy {
199 if (!isDefaultWebProxySet) {
201 if (defaultWebProxy == null)
202 defaultWebProxy = GetDefaultWebProxy ();
205 return defaultWebProxy;
208 /* MS documentation states that a null value would cause an ArgumentNullException
209 * but that's not the way it behaves:
210 * https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304724
212 defaultWebProxy = value;
213 isDefaultWebProxySet = true;
217 internal static IWebProxy InternalDefaultWebProxy {
219 return DefaultWebProxy;
224 [MonoTODO("Needs to respect Module, Proxy.AutoDetect, and Proxy.ScriptLocation config settings")]
225 static IWebProxy GetDefaultWebProxy ()
227 #if CONFIGURATION_DEP
228 DefaultProxySection sec = ConfigurationManager.GetSection ("system.net/defaultProxy") as DefaultProxySection;
232 return GetSystemWebProxy ();
234 ProxyElement pe = sec.Proxy;
236 if ((pe.UseSystemDefault != ProxyElement.UseSystemDefaultValues.False) && (pe.ProxyAddress == null)) {
237 IWebProxy proxy = GetSystemWebProxy ();
239 if (!(proxy is WebProxy))
242 p = (WebProxy) proxy;
246 if (pe.ProxyAddress != null)
247 p.Address = pe.ProxyAddress;
249 if (pe.BypassOnLocal != ProxyElement.BypassOnLocalValues.Unspecified)
250 p.BypassProxyOnLocal = (pe.BypassOnLocal == ProxyElement.BypassOnLocalValues.True);
252 foreach(BypassElement elem in sec.BypassList)
253 p.BypassArrayList.Add(elem.Address);
257 return GetSystemWebProxy ();
263 public virtual void Abort()
265 throw GetMustImplement ();
268 public virtual IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state)
270 throw GetMustImplement ();
273 public virtual IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
275 throw GetMustImplement ();
278 public static WebRequest Create (string requestUriString)
280 if (requestUriString == null)
281 throw new ArgumentNullException ("requestUriString");
282 return Create (new Uri (requestUriString));
285 public static WebRequest Create (Uri requestUri)
287 if (requestUri == null)
288 throw new ArgumentNullException ("requestUri");
289 return GetCreator (requestUri.AbsoluteUri).Create (requestUri);
292 public static WebRequest CreateDefault (Uri requestUri)
294 if (requestUri == null)
295 throw new ArgumentNullException ("requestUri");
296 return GetCreator (requestUri.Scheme).Create (requestUri);
298 static HttpWebRequest SharedCreateHttp (Uri uri)
300 if (uri.Scheme != "http" && uri.Scheme != "https")
301 throw new NotSupportedException ("The uri should start with http or https");
303 return new HttpWebRequest (uri);
306 public static HttpWebRequest CreateHttp (string requestUriString)
308 if (requestUriString == null)
309 throw new ArgumentNullException ("requestUriString");
310 return SharedCreateHttp (new Uri (requestUriString));
313 public static HttpWebRequest CreateHttp (Uri requestUri)
315 if (requestUri == null)
316 throw new ArgumentNullException ("requestUri");
317 return SharedCreateHttp (requestUri);
319 public virtual Stream EndGetRequestStream (IAsyncResult asyncResult)
321 throw GetMustImplement ();
324 public virtual WebResponse EndGetResponse (IAsyncResult asyncResult)
326 throw GetMustImplement ();
329 public virtual Stream GetRequestStream()
331 throw GetMustImplement ();
334 public virtual WebResponse GetResponse()
336 throw GetMustImplement ();
339 // Takes an ArrayList of fileglob-formatted strings and returns an array of Regex-formatted strings
340 private static string[] CreateBypassList (ArrayList al)
342 string[] result = al.ToArray (typeof (string)) as string[];
343 for (int c = 0; c < result.Length; c++)
346 Regex.Escape (result [c]).Replace (@"\*", ".*").Replace (@"\?", ".") +
352 [MonoTODO("Look in other places for proxy config info")]
353 public static IWebProxy GetSystemWebProxy ()
356 return CFNetwork.GetDefaultProxy ();
359 // Return the system web proxy. This only works for ICS+.
360 var androidProxy = AndroidPlatform.GetDefaultProxy ();
361 if (androidProxy != null)
366 int iProxyEnable = (int)Microsoft.Win32.Registry.GetValue ("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyEnable", 0);
368 if (iProxyEnable > 0) {
369 string strHttpProxy = "";
370 bool bBypassOnLocal = false;
371 ArrayList al = new ArrayList ();
373 string strProxyServer = (string)Microsoft.Win32.Registry.GetValue ("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyServer", null);
374 string strProxyOverrride = (string)Microsoft.Win32.Registry.GetValue ("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyOverride", null);
376 if (strProxyServer.Contains ("=")) {
377 foreach (string strEntry in strProxyServer.Split (new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
378 if (strEntry.StartsWith ("http=")) {
379 strHttpProxy = strEntry.Substring (5);
382 } else strHttpProxy = strProxyServer;
384 if (strProxyOverrride != null) {
385 string[] bypassList = strProxyOverrride.Split (new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
387 foreach (string str in bypassList) {
388 if (str != "<local>")
391 bBypassOnLocal = true;
395 return new WebProxy (strHttpProxy, bBypassOnLocal, CreateBypassList (al));
399 if (Platform.IsMacOS)
400 return CFNetwork.GetDefaultProxy ();
402 string address = Environment.GetEnvironmentVariable ("http_proxy");
405 address = Environment.GetEnvironmentVariable ("HTTP_PROXY");
407 if (address != null) {
409 if (!address.StartsWith ("http://"))
410 address = "http://" + address;
412 Uri uri = new Uri (address);
415 if (IPAddress.TryParse (uri.Host, out ip)) {
416 if (IPAddress.Any.Equals (ip)) {
417 UriBuilder builder = new UriBuilder (uri);
418 builder.Host = "127.0.0.1";
420 } else if (IPAddress.IPv6Any.Equals (ip)) {
421 UriBuilder builder = new UriBuilder (uri);
422 builder.Host = "[::1]";
427 bool bBypassOnLocal = false;
428 ArrayList al = new ArrayList ();
429 string bypass = Environment.GetEnvironmentVariable ("no_proxy");
432 bypass = Environment.GetEnvironmentVariable ("NO_PROXY");
434 if (bypass != null) {
435 string[] bypassList = bypass.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
437 foreach (string str in bypassList) {
438 if (str != "*.local")
441 bBypassOnLocal = true;
445 return new WebProxy (uri, bBypassOnLocal, CreateBypassList (al));
446 } catch (UriFormatException) {
453 return new WebProxy ();
457 void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
459 GetObjectData(serializationInfo, streamingContext);
462 protected virtual void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
466 public static bool RegisterPrefix (string prefix, IWebRequestCreate creator)
469 throw new ArgumentNullException ("prefix");
471 throw new ArgumentNullException ("creator");
473 lock (prefixes.SyncRoot) {
474 string lowerCasePrefix = prefix.ToLower (CultureInfo.InvariantCulture);
475 if (prefixes.Contains (lowerCasePrefix))
477 prefixes.Add (lowerCasePrefix, creator);
482 private static IWebRequestCreate GetCreator (string prefix)
484 int longestPrefix = -1;
485 IWebRequestCreate creator = null;
487 prefix = prefix.ToLower (CultureInfo.InvariantCulture);
489 IDictionaryEnumerator e = prefixes.GetEnumerator ();
490 while (e.MoveNext ()) {
491 string key = e.Key as string;
493 if (key.Length <= longestPrefix)
496 if (!prefix.StartsWith (key))
499 longestPrefix = key.Length;
500 creator = (IWebRequestCreate) e.Value;
504 throw new NotSupportedException (prefix);
509 internal static bool IsWindows ()
511 return (int) Environment.OSVersion.Platform < 4;
514 internal static void ClearPrefixes ()
519 internal static void RemovePrefix (string prefix)
521 prefixes.Remove (prefix);
524 internal static void AddPrefix (string prefix, string typeName)
526 Type type = Type.GetType (typeName);
528 throw new ConfigurationException (String.Format ("Type {0} not found", typeName));
529 AddPrefix (prefix, type);
532 internal static void AddPrefix (string prefix, Type type)
534 object o = Activator.CreateInstance (type, true);
535 prefixes [prefix] = o;
538 public virtual Task<Stream> GetRequestStreamAsync ()
540 return Task<Stream>.Factory.FromAsync (BeginGetRequestStream, EndGetRequestStream, null);
543 public virtual Task<WebResponse> GetResponseAsync ()
545 return Task<WebResponse>.Factory.FromAsync (BeginGetResponse, EndGetResponse, null);