f5cb68cc18ce065f31f0ced155ee71fe2a1687e4
[mono.git] / mcs / class / System / System.Net / WebRequest.cs
1 //
2 // System.Net.WebRequest
3 //
4 // Authors:
5 //  Lawrence Pit (loz@cable.a2000.nl)
6 //      Marek Safar (marek.safar@gmail.com)
7 //
8 // Copyright 2011 Xamarin Inc.
9 //
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:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
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.
28 //
29
30 using System;
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Configuration;
34 using System.IO;
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 #if NET_4_5
43 using System.Threading.Tasks;
44 #endif
45
46 #if NET_2_1
47 using ConfigurationException = System.ArgumentException;
48
49 namespace System.Net.Configuration {
50         class Dummy {}
51 }
52 #endif
53
54 namespace System.Net 
55 {
56         [Serializable]
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;
62                 
63                 // Constructors
64                 
65                 static WebRequest ()
66                 {
67 #if NET_2_1
68                         IWebRequestCreate http = new HttpRequestCreator ();
69                         RegisterPrefix ("http", http);
70                         RegisterPrefix ("https", http);
71         #if MOBILE
72                         RegisterPrefix ("file", new FileWebRequestCreator ());
73                         RegisterPrefix ("ftp", new FtpRequestCreator ());
74         #endif
75 #else
76                         defaultCachePolicy = new HttpRequestCachePolicy (HttpRequestCacheLevel.NoCacheNoStore);
77         #if CONFIGURATION_DEP
78                         object cfg = ConfigurationManager.GetSection ("system.net/webRequestModules");
79                         WebRequestModulesSection s = cfg as WebRequestModulesSection;
80                         if (s != null) {
81                                 foreach (WebRequestModuleElement el in
82                                          s.WebRequestModules)
83                                         AddPrefix (el.Prefix, el.Type);
84                                 return;
85                         }
86         #endif
87                         ConfigurationSettings.GetConfig ("system.net/webRequestModules");
88 #endif
89                 }
90                 
91                 protected WebRequest () 
92                 {
93                 }
94                 
95                 protected WebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) 
96                 {
97                 }
98
99                 static Exception GetMustImplement ()
100                 {
101                         return new NotImplementedException ("This method must be implemented in derived classes");
102                 }
103                 
104                 // Properties
105
106                 private AuthenticationLevel authentication_level = AuthenticationLevel.MutualAuthRequested;
107                 
108                 public AuthenticationLevel AuthenticationLevel
109                 {
110                         get {
111                                 return(authentication_level);
112                         }
113                         set {
114                                 authentication_level = value;
115                         }
116                 }
117
118                 [MonoTODO ("Implement the caching system. Currently always returns a policy with the NoCacheNoStore level")]
119                 public virtual RequestCachePolicy CachePolicy
120                 {
121                         get { return DefaultCachePolicy; }
122                         set {
123                         }
124                 }
125                 
126                 public virtual string ConnectionGroupName {
127                         get { throw GetMustImplement (); }
128                         set { throw GetMustImplement (); }
129                 }
130                 
131                 public virtual long ContentLength { 
132                         get { throw GetMustImplement (); }
133                         set { throw GetMustImplement (); }
134                 }
135                 
136                 public virtual string ContentType { 
137                         get { throw GetMustImplement (); }
138                         set { throw GetMustImplement (); }
139                 }
140                 
141                 public virtual ICredentials Credentials { 
142                         get { throw GetMustImplement (); }
143                         set { throw GetMustImplement (); }
144                 }
145
146                 public static RequestCachePolicy DefaultCachePolicy
147                 {
148                         get { return defaultCachePolicy; }
149                         set {
150                                 throw GetMustImplement ();
151                         }
152                 }
153                 
154                 public virtual WebHeaderCollection Headers { 
155                         get { throw GetMustImplement (); }
156                         set { throw GetMustImplement (); }
157                 }
158                 
159                 public TokenImpersonationLevel ImpersonationLevel {
160                         get { throw GetMustImplement (); }
161                         set { throw GetMustImplement (); }
162                 }
163
164                 public virtual string Method { 
165                         get { throw GetMustImplement (); }
166                         set { throw GetMustImplement (); }
167                 }
168                 
169                 public virtual bool PreAuthenticate { 
170                         get { throw GetMustImplement (); }
171                         set { throw GetMustImplement (); }
172                 }
173                 
174                 public virtual IWebProxy Proxy { 
175                         get { throw GetMustImplement (); }
176                         set { throw GetMustImplement (); }
177                 }
178                 
179                 public virtual Uri RequestUri { 
180                         get { throw GetMustImplement (); }
181                 }
182                 
183                 public virtual int Timeout { 
184                         get { throw GetMustImplement (); }
185                         set { throw GetMustImplement (); }
186                 }
187                 
188                 public virtual bool UseDefaultCredentials
189                 {
190                         get {
191                                 throw GetMustImplement ();
192                         }
193                         set {
194                                 throw GetMustImplement ();
195                         }
196                 }
197                 
198 //              volatile static IWebProxy proxy;
199                 static readonly object lockobj = new object ();
200                 
201                 public static IWebProxy DefaultWebProxy {
202                         get {
203                                 if (!isDefaultWebProxySet) {
204                                         lock (lockobj) {
205                                                 if (defaultWebProxy == null)
206                                                         defaultWebProxy = GetDefaultWebProxy ();
207                                         }
208                                 }
209                                 return defaultWebProxy;
210                         }
211                         set {
212                                 /* MS documentation states that a null value would cause an ArgumentNullException
213                                  * but that's not the way it behaves:
214                                  * https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304724
215                                  */
216                                 defaultWebProxy = value;
217                                 isDefaultWebProxySet = true;
218                         }
219                 }
220                 
221                 [MonoTODO("Needs to respect Module, Proxy.AutoDetect, and Proxy.ScriptLocation config settings")]
222                 static IWebProxy GetDefaultWebProxy ()
223                 {
224 #if CONFIGURATION_DEP
225                         DefaultProxySection sec = ConfigurationManager.GetSection ("system.net/defaultProxy") as DefaultProxySection;
226                         WebProxy p;
227                         
228                         if (sec == null)
229                                 return GetSystemWebProxy ();
230                         
231                         ProxyElement pe = sec.Proxy;
232                         
233                         if ((pe.UseSystemDefault != ProxyElement.UseSystemDefaultValues.False) && (pe.ProxyAddress == null)) {
234                                 IWebProxy proxy = GetSystemWebProxy ();
235                                 
236                                 if (!(proxy is WebProxy))
237                                         return proxy;
238                                 
239                                 p = (WebProxy) proxy;
240                         } else
241                                 p = new WebProxy ();
242                         
243                         if (pe.ProxyAddress != null)
244                                 p.Address = pe.ProxyAddress;
245                         
246                         if (pe.BypassOnLocal != ProxyElement.BypassOnLocalValues.Unspecified)
247                                 p.BypassProxyOnLocal = (pe.BypassOnLocal == ProxyElement.BypassOnLocalValues.True);
248                                 
249                         foreach(BypassElement elem in sec.BypassList)
250                                 p.BypassArrayList.Add(elem.Address);
251                         
252                         return p;
253 #else
254                         return GetSystemWebProxy ();
255 #endif
256                 }
257
258                 // Methods
259                 
260                 public virtual void Abort()
261                 {
262                         throw GetMustImplement ();
263                 }
264                 
265                 public virtual IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) 
266                 {
267                         throw GetMustImplement ();
268                 }
269                 
270                 public virtual IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
271                 {
272                         throw GetMustImplement ();
273                 }
274
275                 public static WebRequest Create (string requestUriString) 
276                 {
277                         if (requestUriString == null)
278                                 throw new ArgumentNullException ("requestUriString");
279                         return Create (new Uri (requestUriString));
280                 }
281                                 
282                 public static WebRequest Create (Uri requestUri) 
283                 {
284                         if (requestUri == null)
285                                 throw new ArgumentNullException ("requestUri");
286                         return GetCreator (requestUri.AbsoluteUri).Create (requestUri);
287                 }
288                 
289                 public static WebRequest CreateDefault (Uri requestUri)
290                 {
291                         if (requestUri == null)
292                                 throw new ArgumentNullException ("requestUri");
293                         return GetCreator (requestUri.Scheme).Create (requestUri);
294                 }
295 #if NET_4_5 || MOBILE   
296                 [MonoTODO ("for portable library support")]
297                 public static HttpWebRequest CreateHttp (string requestUriString)
298                 {
299                         throw new NotImplementedException ();
300                 }
301                         
302                 [MonoTODO ("for portable library support")]
303                 public static HttpWebRequest CreateHttp (Uri requestUri)
304                 {
305                         throw new NotImplementedException ();
306                 }
307 #endif
308                 public virtual Stream EndGetRequestStream (IAsyncResult asyncResult)
309                 {
310                         throw GetMustImplement ();
311                 }
312                 
313                 public virtual WebResponse EndGetResponse (IAsyncResult asyncResult)
314                 {
315                         throw GetMustImplement ();
316                 }
317                 
318                 public virtual Stream GetRequestStream()
319                 {
320                         throw GetMustImplement ();
321                 }
322                 
323                 public virtual WebResponse GetResponse()
324                 {
325                         throw GetMustImplement ();
326                 }
327                 
328                 [MonoTODO("Look in other places for proxy config info")]
329                 public static IWebProxy GetSystemWebProxy ()
330                 {
331 #if !NET_2_1
332                         if (IsWindows ()) {
333                                 int iProxyEnable = (int)Microsoft.Win32.Registry.GetValue ("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyEnable", 0);
334
335                                 if (iProxyEnable > 0) {
336                                         string strHttpProxy = "";                                       
337                                         bool bBypassOnLocal = false;
338                                         ArrayList al = new ArrayList ();
339                                         
340                                         string strProxyServer = (string)Microsoft.Win32.Registry.GetValue ("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyServer", null);
341                                         string strProxyOverrride = (string)Microsoft.Win32.Registry.GetValue ("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "ProxyOverride", null);
342                                         
343                                         if (strProxyServer.Contains ("=")) {
344                                                 foreach (string strEntry in strProxyServer.Split (new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
345                                                         if (strEntry.StartsWith ("http=")) {
346                                                                 strHttpProxy = strEntry.Substring (5);
347                                                                 break;
348                                                         }
349                                         } else strHttpProxy = strProxyServer;
350                                         
351                                         if (strProxyOverrride != null) {                                                
352                                                 string[] bypassList = strProxyOverrride.Split (new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
353                                         
354                                                 foreach (string str in bypassList) {
355                                                         if (str != "<local>")
356                                                                 al.Add (str);
357                                                         else
358                                                                 bBypassOnLocal = true;
359                                                 }
360                                         }
361                                         
362                                         return new WebProxy (strHttpProxy, bBypassOnLocal, al.ToArray (typeof(string)) as string[]);
363                                 }
364                         } else {
365 #endif
366                                 if (Platform.IsMacOS)
367                                         return CFNetwork.GetDefaultProxy ();
368                                 
369                                 string address = Environment.GetEnvironmentVariable ("http_proxy");
370
371                                 if (address == null)
372                                         address = Environment.GetEnvironmentVariable ("HTTP_PROXY");
373                                 
374                                 if (address != null) {
375                                         try {
376                                                 if (!address.StartsWith ("http://"))
377                                                         address = "http://" + address;
378
379                                                 Uri uri = new Uri (address);
380                                                 IPAddress ip;
381                                                 
382                                                 if (IPAddress.TryParse (uri.Host, out ip)) {
383                                                         if (IPAddress.Any.Equals (ip)) {
384                                                                 UriBuilder builder = new UriBuilder (uri);
385                                                                 builder.Host = "127.0.0.1";
386                                                                 uri = builder.Uri;
387                                                         } else if (IPAddress.IPv6Any.Equals (ip)) {
388                                                                 UriBuilder builder = new UriBuilder (uri);
389                                                                 builder.Host = "[::1]";
390                                                                 uri = builder.Uri;
391                                                         }
392                                                 }
393                                                 
394                                                 bool bBypassOnLocal = false;                                            
395                                                 ArrayList al = new ArrayList ();
396                                                 string bypass = Environment.GetEnvironmentVariable ("no_proxy");
397                                                 
398                                                 if (bypass == null)
399                                                         bypass = Environment.GetEnvironmentVariable ("NO_PROXY");
400                                                 
401                                                 if (bypass != null) {
402                                                         string[] bypassList = bypass.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
403                                                 
404                                                         foreach (string str in bypassList) {
405                                                                 if (str != "*.local")
406                                                                         al.Add (str);
407                                                                 else
408                                                                         bBypassOnLocal = true;
409                                                         }
410                                                 }
411                                                 
412                                                 return new WebProxy (uri, bBypassOnLocal, al.ToArray (typeof(string)) as string[]);
413                                         } catch (UriFormatException) {
414                                         }
415                                 }
416 #if !NET_2_1
417                         }
418 #endif
419                         
420                         return new WebProxy ();
421                 }
422
423                 void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
424                 {
425                         throw new NotSupportedException ();
426                 }
427
428                 protected virtual void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
429                 {
430                         throw GetMustImplement ();
431                 }
432
433                 public static bool RegisterPrefix (string prefix, IWebRequestCreate creator)
434                 {
435                         if (prefix == null)
436                                 throw new ArgumentNullException ("prefix");
437                         if (creator == null)
438                                 throw new ArgumentNullException ("creator");
439                         
440                         lock (prefixes.SyncRoot) {
441                                 string lowerCasePrefix = prefix.ToLower (CultureInfo.InvariantCulture);
442                                 if (prefixes.Contains (lowerCasePrefix))
443                                         return false;
444                                 prefixes.Add (lowerCasePrefix, creator);
445                         }
446                         return true;
447                 }
448                 
449                 private static IWebRequestCreate GetCreator (string prefix)
450                 {
451                         int longestPrefix = -1;
452                         IWebRequestCreate creator = null;
453
454                         prefix = prefix.ToLower (CultureInfo.InvariantCulture);
455
456                         IDictionaryEnumerator e = prefixes.GetEnumerator ();
457                         while (e.MoveNext ()) {
458                                 string key = e.Key as string;
459
460                                 if (key.Length <= longestPrefix) 
461                                         continue;
462                                 
463                                 if (!prefix.StartsWith (key))
464                                         continue;
465                                         
466                                 longestPrefix = key.Length;
467                                 creator = (IWebRequestCreate) e.Value;
468                         }
469                         
470                         if (creator == null) 
471                                 throw new NotSupportedException (prefix);
472                                 
473                         return creator;
474                 }
475                 
476                 internal static bool IsWindows ()
477                 {
478                         return (int) Environment.OSVersion.Platform < 4;
479                 }
480
481                 internal static void ClearPrefixes ()
482                 {
483                         prefixes.Clear ();
484                 }
485
486                 internal static void RemovePrefix (string prefix)
487                 {
488                         prefixes.Remove (prefix);
489                 }
490
491                 internal static void AddPrefix (string prefix, string typeName)
492                 {
493                         Type type = Type.GetType (typeName);
494                         if (type == null)
495                                 throw new ConfigurationException (String.Format ("Type {0} not found", typeName));
496                         AddPrefix (prefix, type);
497                 }
498
499                 internal static void AddPrefix (string prefix, Type type)
500                 {
501                         object o = Activator.CreateInstance (type, true);
502                         prefixes [prefix] = o;
503                 }
504
505 #if NET_4_5
506                 public virtual Task<Stream> GetRequestStreamAsync ()
507                 {
508                         return Task<Stream>.Factory.FromAsync (BeginGetRequestStream, EndGetRequestStream, null);
509                 }
510
511                 public virtual Task<WebResponse> GetResponseAsync ()
512                 {
513                         return Task<WebResponse>.Factory.FromAsync (BeginGetResponse, EndGetResponse, null);
514                 }
515 #endif
516
517         }
518 }