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