/mcs/class/System/System.Net/WebRequest.cs
C# | 517 lines | 396 code | 85 blank | 36 comment | 64 complexity | 8a3b7077767dd845beb3745546dc08e9 MD5 | raw file
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
30using System;
31using System.Collections;
32using System.Collections.Specialized;
33using System.Configuration;
34using System.IO;
35using System.Reflection;
36using System.Runtime.Serialization;
37using System.Globalization;
38using System.Net.Configuration;
39using System.Net.Security;
40using System.Net.Cache;
41using System.Security.Principal;
42#if NET_4_5
43using System.Threading.Tasks;
44#endif
45
46#if NET_2_1
47using ConfigurationException = System.ArgumentException;
48
49namespace System.Net.Configuration {
50 class Dummy {}
51}
52#endif
53
54namespace 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}