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