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