Merge pull request #3040 from xmcclure/debugger-step-recursive
[mono.git] / mcs / class / referencesource / System / net / System / Net / WebRequest.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="WebRequest.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 #if MONO
8 #undef FEATURE_PAL
9 #endif
10 namespace System.Net {
11     using System.Collections;
12     using System.Collections.Generic;
13     using System.Configuration;
14     using System.Diagnostics.CodeAnalysis;
15     using System.Diagnostics.Contracts;
16     using System.Diagnostics.Tracing;
17     using System.Globalization;
18     using System.IO;
19     using System.Net.Cache;
20     using System.Net.Configuration;
21     using System.Reflection;
22     using System.Runtime.Serialization;
23     using System.Security.Permissions;
24     using System.Security.Principal;
25     using System.Threading;
26     using System.Threading.Tasks;
27     using System.Net.Security;
28     using System.ComponentModel;
29     using System.Security;
30     //
31     // WebRequest - the base class of all Web resource/protocol objects. Provides
32     // common methods, data and proprties for making the top level request
33     //
34
35     /// <devdoc>
36     ///    <para>A request to a Uniform Resource Identifier (Uri). This
37     ///       is an abstract class.</para>
38     /// </devdoc>
39     [Serializable]
40     public abstract class WebRequest : MarshalByRefObject, ISerializable
41     {
42 #if FEATURE_PAL // ROTORTODO - after speed ups (like real JIT and GC) remove this one
43 #if DEBUG
44         internal const int DefaultTimeout = 100000 * 10;
45 #else // DEBUG
46         internal const int DefaultTimeout = 100000 * 5;
47 #endif // DEBUG
48 #else // FEATURE_PAL
49         internal const int DefaultTimeout = 100000; // default timeout is 100 seconds (ASP .NET is 90 seconds)
50 #endif // FEATURE_PAL
51         private static volatile ArrayList s_PrefixList;
52         private static Object s_InternalSyncObject;
53         private static TimerThread.Queue s_DefaultTimerQueue = TimerThread.CreateQueue(DefaultTimeout);
54
55 #if !FEATURE_PAL
56         private  AuthenticationLevel m_AuthenticationLevel;
57         private  TokenImpersonationLevel m_ImpersonationLevel;
58 #endif
59
60         private RequestCachePolicy      m_CachePolicy;
61         private RequestCacheProtocol    m_CacheProtocol;
62         private RequestCacheBinding     m_CacheBinding;
63
64 #region designer support for System.Windows.dll
65         internal class DesignerWebRequestCreate : IWebRequestCreate
66         {
67             public WebRequest Create(Uri uri)
68             {
69                 return WebRequest.Create(uri);
70             }
71         }
72         private static DesignerWebRequestCreate webRequestCreate = new DesignerWebRequestCreate();
73         //introduced for supporting design-time loading of System.Windows.dll
74         [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
75         [EditorBrowsable(EditorBrowsableState.Never)]
76         public virtual IWebRequestCreate CreatorInstance { get { return webRequestCreate; } }
77
78         //introduced for supporting design-time loading of System.Windows.dll
79         [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
80         [EditorBrowsable(EditorBrowsableState.Never)]
81         public static void RegisterPortableWebRequestCreator(IWebRequestCreate creator) { }       
82 #endregion        
83
84         private static Object InternalSyncObject {
85             get {
86                 if (s_InternalSyncObject == null) {
87                     Object o = new Object();
88                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
89                 }
90                 return s_InternalSyncObject;
91             }
92         }
93
94         internal static TimerThread.Queue DefaultTimerQueue {
95             get {
96                 return s_DefaultTimerQueue;
97             }
98         }
99
100         /*++
101
102             Create - Create a WebRequest.
103
104             This is the main creation routine. We take a Uri object, look
105             up the Uri in the prefix match table, and invoke the appropriate
106             handler to create the object. We also have a parameter that
107             tells us whether or not to use the whole Uri or just the
108             scheme portion of it.
109
110             Input:
111
112                 RequestUri          - Uri object for request.
113                 UseUriBase          - True if we're only to look at the scheme
114                                         portion of the Uri.
115
116             Returns:
117
118                 Newly created WebRequest.
119         --*/
120
121         private static WebRequest Create(Uri requestUri, bool useUriBase) {
122             if(Logging.On)Logging.Enter(Logging.Web, "WebRequest", "Create", requestUri.ToString());
123
124             string LookupUri;
125             WebRequestPrefixElement Current = null;
126             bool Found = false;
127
128             if (!useUriBase)
129             {
130                 LookupUri = requestUri.AbsoluteUri;
131             }
132             else {
133
134                 //
135                 // schemes are registered as <schemeName>":", so add the separator
136                 // to the string returned from the Uri object
137                 //
138
139                 LookupUri = requestUri.Scheme + ':';
140             }
141
142             int LookupLength = LookupUri.Length;
143
144             // Copy the prefix list so that if it is updated it will
145             // not affect us on this thread.
146
147             ArrayList prefixList = PrefixList;
148
149             // Look for the longest matching prefix.
150
151             // Walk down the list of prefixes. The prefixes are kept longest
152             // first. When we find a prefix that is shorter or the same size
153             // as this Uri, we'll do a compare to see if they match. If they
154             // do we'll break out of the loop and call the creator.
155
156             for (int i = 0; i < prefixList.Count; i++) {
157                 Current = (WebRequestPrefixElement)prefixList[i];
158
159                 //
160                 // See if this prefix is short enough.
161                 //
162
163                 if (LookupLength >= Current.Prefix.Length) {
164
165                     //
166                     // It is. See if these match.
167                     //
168
169                     if (String.Compare(Current.Prefix,
170                                        0,
171                                        LookupUri,
172                                        0,
173                                        Current.Prefix.Length,
174                                        StringComparison.OrdinalIgnoreCase ) == 0) {
175
176                         //
177                         // These match. Remember that we found it and break
178                         // out.
179                         //
180
181                         Found = true;
182                         break;
183                     }
184                 }
185             }
186
187             WebRequest webRequest = null;
188
189             if (Found) {
190
191                 //
192                 // We found a match, so just call the creator and return what it
193                 // does.
194                 //
195
196                 webRequest = Current.Creator.Create(requestUri);
197                 if(Logging.On)Logging.Exit(Logging.Web, "WebRequest", "Create", webRequest);
198                 return webRequest;
199             }
200
201             if(Logging.On)Logging.Exit(Logging.Web, "WebRequest", "Create", null);
202
203             //
204             // Otherwise no match, throw an exception.
205             //
206
207             throw new NotSupportedException(SR.GetString(SR.net_unknown_prefix));
208         }
209
210         /*++
211
212             Create - Create a WebRequest.
213
214             An overloaded utility version of the real Create that takes a
215             string instead of an Uri object.
216
217
218             Input:
219
220                 RequestString       - Uri string to create.
221
222             Returns:
223
224                 Newly created WebRequest.
225         --*/
226
227         /// <devdoc>
228         ///    <para>
229         ///       Creates a new <see cref='System.Net.WebRequest'/>
230         ///       instance for
231         ///       the specified Uri scheme.
232         ///    </para>
233         /// </devdoc>
234         public static WebRequest Create(string requestUriString) {
235             if (requestUriString == null) {
236                 throw new ArgumentNullException("requestUriString");
237             }
238             // In .NET FX v4.0, custom IWebRequestCreate implementations can 
239             // cause this to return null.  Consider tightening this in the future.
240             //Contract.Ensures(Contract.Result<WebRequest>() != null);
241
242             return Create(new Uri(requestUriString), false);
243         }
244
245         /*++
246
247             Create - Create a WebRequest.
248
249             Another overloaded version of the Create function that doesn't
250             take the UseUriBase parameter.
251
252             Input:
253
254                 RequestUri          - Uri object for request.
255
256             Returns:
257
258                 Newly created WebRequest.
259         --*/
260
261         /// <devdoc>
262         ///    <para>
263         ///       Creates a new <see cref='System.Net.WebRequest'/> instance for the specified Uri scheme.
264         ///    </para>
265         /// </devdoc>
266         public static WebRequest Create(Uri requestUri) {
267             if (requestUri == null) {
268                 throw new ArgumentNullException("requestUri");
269             }
270             // In .NET FX v4.0, custom IWebRequestCreate implementations can 
271             // cause this to return null.  Consider tightening this in the future.
272             //Contract.Ensures(Contract.Result<WebRequest>() != null);
273
274             return Create(requestUri, false);
275         }
276
277         /*++
278
279             CreateDefault - Create a default WebRequest.
280
281             This is the creation routine that creates a default WebRequest.
282             We take a Uri object and pass it to the base create routine,
283             setting the useUriBase parameter to true.
284
285             Input:
286
287                 RequestUri          - Uri object for request.
288
289             Returns:
290
291                 Newly created WebRequest.
292         --*/
293         /// <devdoc>
294         ///    <para>[To be supplied.]</para>
295         /// </devdoc>
296         public static WebRequest CreateDefault(Uri requestUri) {
297             if (requestUri == null) {
298                 throw new ArgumentNullException("requestUri");
299             }
300             // In .NET FX v4.0, custom IWebRequestCreate implementations can 
301             // cause this to return null.  Consider tightening this in the future.
302             //Contract.Ensures(Contract.Result<WebRequest>() != null);
303
304             return Create(requestUri, true);
305         }
306         
307         // For portability
308         public static HttpWebRequest CreateHttp(string requestUriString) {
309             if (requestUriString == null) {
310                 throw new ArgumentNullException("requestUriString");
311             }
312             return CreateHttp(new Uri(requestUriString));
313         }
314
315         // For portability
316         public static HttpWebRequest CreateHttp(Uri requestUri) {
317             if (requestUri == null) {
318                 throw new ArgumentNullException("requestUri");
319             }
320             if ((requestUri.Scheme != Uri.UriSchemeHttp) && (requestUri.Scheme != Uri.UriSchemeHttps)) {
321                 throw new NotSupportedException(SR.GetString(SR.net_unknown_prefix));
322             }
323             return (HttpWebRequest)CreateDefault(requestUri);
324         }
325
326         /*++
327
328             RegisterPrefix - Register an Uri prefix for creating WebRequests.
329
330             This function registers a prefix for creating WebRequests. When an
331             user wants to create a WebRequest, we scan a table looking for a
332             longest prefix match for the Uri they're passing. We then invoke
333             the sub creator for that prefix. This function puts entries in
334             that table.
335
336             We don't allow duplicate entries, so if there is a dup this call
337             will fail.
338
339         Input:
340
341             Prefix           - Represents Uri prefix being registered.
342             Creator         - Interface for sub creator.
343
344         Returns:
345
346             True if the registration worked, false otherwise.
347
348         --*/
349         /// <devdoc>
350         ///    <para>
351         ///       Registers a <see cref='System.Net.WebRequest'/> descendent
352         ///       for a specific Uniform Resource Identifier.
353         ///    </para>
354         /// </devdoc>
355         public static bool RegisterPrefix(string prefix, IWebRequestCreate creator) {
356
357             bool Error = false;
358             int i;
359             WebRequestPrefixElement Current;
360
361             if (prefix == null) {
362                 throw new ArgumentNullException("prefix");
363             }
364             if (creator == null) {
365                 throw new ArgumentNullException("creator");
366             }
367
368 #if !DISABLE_CAS_USE
369             ExceptionHelper.WebPermissionUnrestricted.Demand();
370 #endif
371
372             // Lock this object, then walk down PrefixList looking for a place to
373             // to insert this prefix.
374
375             lock(InternalSyncObject) {
376                 //
377                 // clone the object and update the clone thus
378                 // allowing other threads to still read from it
379                 //
380
381                 ArrayList prefixList = (ArrayList)PrefixList.Clone();
382
383                 // As AbsoluteUri is used later for Create, account for formating changes 
384                 // like Unicode escaping, default ports, etc.
385                 Uri tempUri;
386                 if (Uri.TryCreate(prefix, UriKind.Absolute, out tempUri))
387                 {
388                     String cookedUri = tempUri.AbsoluteUri;
389
390                     // Special case for when a partial host matching is requested, drop the added trailing slash
391                     // IE: http://host could match host or host.domain
392                     if (!prefix.EndsWith("/", StringComparison.Ordinal) 
393                         && tempUri.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, 
394                             UriFormat.UriEscaped)
395                             .Equals("/"))
396                         cookedUri = cookedUri.Substring(0, cookedUri.Length - 1);
397
398                     prefix = cookedUri;
399                 }
400
401                 i = 0;
402
403                 // The prefix list is sorted with longest entries at the front. We
404                 // walk down the list until we find a prefix shorter than this
405                 // one, then we insert in front of it. Along the way we check
406                 // equal length prefixes to make sure this isn't a dupe.
407
408                 while (i < prefixList.Count) {
409                     Current = (WebRequestPrefixElement)prefixList[i];
410
411                     // See if the new one is longer than the one we're looking at.
412
413                     if (prefix.Length > Current.Prefix.Length) {
414                         // It is. Break out of the loop here.
415                         break;
416                     }
417
418                     // If these are of equal length, compare them.
419
420                     if (prefix.Length == Current.Prefix.Length) {
421                         // They're the same length.
422                         if (String.Compare(Current.Prefix, prefix, StringComparison.OrdinalIgnoreCase) == 0) {
423                             // ...and the strings are identical. This is an error.
424
425                             Error = true;
426                             break;
427                         }
428                     }
429                     i++;
430                 }
431
432                 // When we get here either i contains the index to insert at or
433                 // we've had an error, in which case Error is true.
434
435                 if (!Error) {
436                     // No error, so insert.
437
438                     prefixList.Insert(i,
439                                         new WebRequestPrefixElement(prefix, creator)
440                                        );
441
442                     //
443                     // no error, assign the clone to the static object, other
444                     // threads using it will have copied the oriignal object already
445                     //
446                     PrefixList = prefixList;
447                 }
448             }
449             return !Error;
450         }
451
452         /*
453         public static bool UnregisterPrefix(string prefix) {
454             if (prefix == null) {
455                 throw new ArgumentNullException("prefix");
456             }
457             ExceptionHelper.WebPermissionUnrestricted.Demand();
458
459             // Lock this object, then walk down PrefixList looking for a place to
460             // to insert this prefix.
461
462             lock(InternalSyncObject) {
463                 //
464                 // clone the object and update the clone thus
465                 // allowing other threads to still read from it
466                 //
467
468                 ArrayList prefixList = (ArrayList) PrefixList.Clone();
469
470                 int i = 0;
471                 WebRequestPrefixElement Current;
472
473                 // The prefix list is sorted with longest entries at the front. We
474                 // walk down the list until we find a prefix shorter than this
475                 // one, then we insert in front of it. Along the way we check
476                 // equal length prefixes to make sure this isn't a dupe.
477                 while (i < prefixList.Count) {
478                     Current = (WebRequestPrefixElement)prefixList[i];
479
480                     // See if the new one is longer than the one we're looking at.
481
482                     if (prefix.Length > Current.Prefix.Length) {
483                         return fasle;
484                     }
485
486                     // If these are of equal length, compare them.
487
488                     if (prefix.Length == Current.Prefix.Length) {
489                         // They're the same length.
490                         if (String.Compare(Current.Prefix, prefix, StringComparison.OrdinalIgnoreCase ) == 0) {
491                             prefixList.RemoveAt(i);
492                             PrefixList = prefixList;
493                             return true;
494                         }
495                     }
496                     i++;
497                 }
498             }
499
500             return false;
501
502         }
503         */
504
505         /*++
506
507             PrefixList - Returns And Initialize our prefix list.
508
509
510             This is the method that initializes the prefix list. We create
511             an ArrayList for the PrefixList, then an HttpRequestCreator object,
512             and then we register the HTTP and HTTPS prefixes.
513
514             Input: Nothing
515
516             Returns: true
517
518         --*/
519         internal static ArrayList PrefixList {
520
521             get {
522                 //
523                 // GetConfig() might use us, so we have a circular dependency issue,
524                 // that causes us to nest here, we grab the lock, only
525                 // if we haven't initialized.
526                 //
527                 if (s_PrefixList == null) {
528
529                     lock (InternalSyncObject) {
530                         if (s_PrefixList == null) {
531                             GlobalLog.Print("WebRequest::Initialize(): calling ConfigurationManager.GetSection()");
532 #if MONO
533                             s_PrefixList = PopulatePrefixList ();
534 #else
535                             s_PrefixList = WebRequestModulesSectionInternal.GetSection().WebRequestModules;
536 #endif
537                         }
538                     }
539                 }
540
541                 return s_PrefixList;
542             }
543             set {
544                 s_PrefixList = value;
545             }
546         }
547
548 #if MONO
549         static ArrayList PopulatePrefixList ()
550         {
551             var res = new ArrayList();
552
553 #if MOBILE || !CONFIGURATION_DEP
554             IWebRequestCreate http = new HttpRequestCreator ();
555             res.Add(new WebRequestPrefixElement("http", http));
556             res.Add(new WebRequestPrefixElement("https", http));
557             res.Add(new WebRequestPrefixElement("file", new FileWebRequestCreator ()));
558             res.Add(new WebRequestPrefixElement("ftp", new FtpRequestCreator ()));
559 #else
560             object cfg = ConfigurationManager.GetSection ("system.net/webRequestModules");
561             WebRequestModulesSection s = cfg as WebRequestModulesSection;
562             if (s != null) {
563                 foreach (WebRequestModuleElement el in s.WebRequestModules)
564                     res.Add (new WebRequestPrefixElement(el.Prefix, el.Type));
565             }
566 #endif
567             return res;
568         }
569 #endif
570
571
572         // constructors
573
574         /// <devdoc>
575         ///    <para>
576         ///       Initializes a new instance of the <see cref='System.Net.WebRequest'/>
577         ///       class.
578         ///    </para>
579         /// </devdoc>
580
581         protected WebRequest()
582         {
583 #if !FEATURE_PAL
584             // Defautl values are set as per V1.0 behavior
585             m_ImpersonationLevel = TokenImpersonationLevel.Delegation;
586             m_AuthenticationLevel= AuthenticationLevel.MutualAuthRequested;
587 #endif
588         }
589         //
590         // ISerializable constructor
591         //
592         /// <devdoc>
593         ///    <para>[To be supplied.]</para>
594         /// </devdoc>
595         protected WebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext) {
596         }
597
598         //
599         // ISerializable method
600         //
601         /// <internalonly/>
602         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
603         [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)]
604         void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
605         {
606             GetObjectData(serializationInfo, streamingContext);
607         }
608
609         //
610         // FxCop: Provide a way for inherited classes to access base.GetObjectData in case they also implement ISerializable.
611         //
612         [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
613         protected virtual void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
614         {
615         }
616
617         // This is a shortcut that would set the default policy for HTTP/HTTPS.
618         // The default policy is overridden by any prefix-registered policy.
619         // Will demand permission for set{}
620         public static RequestCachePolicy DefaultCachePolicy {
621             get {
622                 return RequestCacheManager.GetBinding(string.Empty).Policy;
623             }
624             set {
625 #if !DISABLE_CAS_USE
626                 // This is a replacement of RequestCachePermission demand since we are not including the latest in the product.
627                 ExceptionHelper.WebPermissionUnrestricted.Demand();
628 #endif
629
630                 RequestCacheBinding binding = RequestCacheManager.GetBinding(string.Empty);
631                 RequestCacheManager.SetBinding(string.Empty, new RequestCacheBinding(binding.Cache, binding.Validator, value));
632             }
633         }
634
635         //
636         //
637         public virtual RequestCachePolicy CachePolicy {
638             get {
639                 return m_CachePolicy;
640             }
641             set
642             {
643                 // Delayed creation of CacheProtocol until caching is actually turned on.
644                 InternalSetCachePolicy(value);
645             }
646         }
647
648
649         void InternalSetCachePolicy(RequestCachePolicy policy){
650             // Delayed creation of CacheProtocol until caching is actually turned on.
651             if (m_CacheBinding != null &&
652                 m_CacheBinding.Cache != null &&
653                 m_CacheBinding.Validator != null &&
654                 CacheProtocol == null &&
655                 policy != null &&
656                 policy.Level != RequestCacheLevel.BypassCache)
657             {
658                 CacheProtocol = new RequestCacheProtocol(m_CacheBinding.Cache, m_CacheBinding.Validator.CreateValidator());
659             }
660
661             m_CachePolicy = policy;
662         }
663
664
665         /// <devdoc>
666         ///    <para>When overridden in a derived class, gets and
667         ///       sets
668         ///       the
669         ///       protocol method used in this request. Default value should be
670         ///       "GET".</para>
671         /// </devdoc>
672         public virtual string Method {
673             get {
674                 throw ExceptionHelper.PropertyNotImplementedException;
675             }
676             set {
677                 throw ExceptionHelper.PropertyNotImplementedException;
678             }
679         }
680
681
682         /// <devdoc>
683         /// <para>When overridden in a derived class, gets a <see cref='Uri'/>
684         /// instance representing the resource associated with
685         /// the request.</para>
686         /// </devdoc>
687         public virtual Uri RequestUri {                               // read-only
688             get {
689                 throw ExceptionHelper.PropertyNotImplementedException;
690             }
691         }
692
693         //
694         // This is a group of connections that may need to be used for
695         //  grouping connecitons.
696         //
697         /// <devdoc>
698         /// </devdoc>
699         public virtual string ConnectionGroupName {
700             get {
701                 throw ExceptionHelper.PropertyNotImplementedException;
702             }
703             set {
704                 throw ExceptionHelper.PropertyNotImplementedException;
705             }
706         }
707
708
709         /*++
710
711             Headers  - Gets any request specific headers associated
712              with this request, this is simply a name/value pair collection
713
714             Input: Nothing.
715
716             Returns: This property returns WebHeaderCollection.
717
718                     read-only
719
720         --*/
721
722         /// <devdoc>
723         ///    <para>When overridden in a derived class,
724         ///       gets
725         ///       a collection of header name-value pairs associated with this
726         ///       request.</para>
727         /// </devdoc>
728         public virtual WebHeaderCollection Headers {
729             get {
730                 Contract.Ensures(Contract.Result<WebHeaderCollection>() != null);
731                 throw ExceptionHelper.PropertyNotImplementedException;
732             }
733             set {
734                 throw ExceptionHelper.PropertyNotImplementedException;
735             }
736         }
737
738
739         /// <devdoc>
740         ///    <para>When
741         ///       overridden in a derived class, gets
742         ///       and sets
743         ///       the
744         ///       content length of request data being sent.</para>
745         /// </devdoc>
746         public virtual long ContentLength {
747             get {
748                 throw ExceptionHelper.PropertyNotImplementedException;
749             }
750             set {
751                 throw ExceptionHelper.PropertyNotImplementedException;
752             }
753         }
754
755         /// <devdoc>
756         ///    <para>When
757         ///       overridden in a derived class, gets
758         ///       and
759         ///       sets
760         ///       the content type of the request data being sent.</para>
761         /// </devdoc>
762         public virtual string ContentType {
763             get {
764                 throw ExceptionHelper.PropertyNotImplementedException;
765             }
766             set {
767                 throw ExceptionHelper.PropertyNotImplementedException;
768             }
769         }
770
771         /// <devdoc>
772         ///     <para>When overridden in a derived class, gets and sets the network
773         ///       credentials used for authentication to this Uri.</para>
774         /// </devdoc>
775         public virtual ICredentials Credentials {
776             get {
777                 throw ExceptionHelper.PropertyNotImplementedException;
778             }
779             set {
780                 throw ExceptionHelper.PropertyNotImplementedException;
781             }
782         }
783
784         /// <devdoc>
785         ///    <para>Sets Credentials to CredentialCache.DefaultCredentials</para>
786         /// </devdoc>
787         public virtual bool UseDefaultCredentials  {
788             get {
789                 throw ExceptionHelper.PropertyNotImplementedException;
790             }
791             set {
792                 throw ExceptionHelper.PropertyNotImplementedException;
793             }
794         }
795
796         /// <devdoc>
797         ///    <para>When overridden in a derived class,
798         ///       gets and set proxy info. </para>
799         /// </devdoc>
800         public virtual IWebProxy Proxy {
801             get {
802                 throw ExceptionHelper.PropertyNotImplementedException;
803             }
804             set {
805                 throw ExceptionHelper.PropertyNotImplementedException;
806             }
807         }
808
809         /// <devdoc>
810         ///    <para>When overridden in a derived class,
811         ///       enables or disables pre-authentication.</para>
812         /// </devdoc>
813         public virtual bool PreAuthenticate {
814             get {
815                 throw ExceptionHelper.PropertyNotImplementedException;
816             }
817             set {
818                 throw ExceptionHelper.PropertyNotImplementedException;
819             }
820         }
821
822         //
823         // Timeout in milliseconds, if request  takes longer
824         // than timeout, a WebException is thrown
825         //
826         //UEUE
827         /// <devdoc>
828         ///    <para>[To be supplied.]</para>
829         /// </devdoc>
830         public virtual int Timeout {
831             get {
832                 throw ExceptionHelper.PropertyNotImplementedException;
833             }
834             set {
835                 throw ExceptionHelper.PropertyNotImplementedException;
836             }
837         }
838
839
840         /// <devdoc>
841         ///    <para>When overridden in a derived class,
842         ///       returns a <see cref='System.IO.Stream'/> object that is used for writing data
843         ///       to the resource identified by <see cref='WebRequest.RequestUri'/>
844         ///       .</para>
845         /// </devdoc>
846         public virtual Stream GetRequestStream() {
847             throw ExceptionHelper.MethodNotImplementedException;
848         }
849
850         /// <devdoc>
851         ///    <para>When overridden in a derived class,
852         ///       returns the response
853         ///       to an Internet request.</para>
854         /// </devdoc>
855         public virtual WebResponse GetResponse() {
856             Contract.Ensures(Contract.Result<WebResponse>() != null);
857
858             throw ExceptionHelper.MethodNotImplementedException;
859         }
860
861         /// <devdoc>
862         ///    <para>Asynchronous version of GetResponse.</para>
863         /// </devdoc>
864         [HostProtection(ExternalThreading=true)]
865         public virtual IAsyncResult BeginGetResponse(AsyncCallback callback, object state) {
866             throw ExceptionHelper.MethodNotImplementedException;
867         }
868
869
870         /// <devdoc>
871         ///    <para>Returns a WebResponse object.</para>
872         /// </devdoc>
873         public virtual WebResponse EndGetResponse(IAsyncResult asyncResult) {
874             throw ExceptionHelper.MethodNotImplementedException;
875         }
876
877         /// <devdoc>
878         ///    <para>Asynchronous version of GetRequestStream
879         ///       method.</para>
880         /// </devdoc>
881         [HostProtection(ExternalThreading=true)]
882         public virtual IAsyncResult BeginGetRequestStream(AsyncCallback callback, Object state) {
883             throw ExceptionHelper.MethodNotImplementedException;
884         }
885
886         /// <devdoc>
887         /// <para>Returns a <see cref='System.IO.Stream'/> object that is used for writing data to the resource
888         ///    identified by <see cref='System.Net.WebRequest.RequestUri'/>
889         ///    .</para>
890         /// </devdoc>
891         public virtual Stream EndGetRequestStream(IAsyncResult asyncResult) {
892             throw ExceptionHelper.MethodNotImplementedException;
893         }
894
895         // Offload to a different thread to avoid blocking the caller durring request submission.
896         [HostProtection(ExternalThreading = true)]
897         public virtual Task<Stream> GetRequestStreamAsync()
898         {
899             IWebProxy proxy = null;
900             try { proxy = Proxy; }
901             catch (NotImplementedException) { }
902
903             // Preserve context for authentication
904             if (ExecutionContext.IsFlowSuppressed() 
905                 && (UseDefaultCredentials || Credentials != null
906                     || (proxy != null && proxy.Credentials != null)))
907             {
908                 WindowsIdentity currentUser = SafeCaptureIdenity();
909
910                 // When flow is suppressed we would lose track of the current user across this thread switch.
911                 // Flow manually so that UseDefaultCredentials will work. BeginGetRequestStream will
912                 // take over from there.
913                 return Task.Run(() =>
914                 {
915                     using (currentUser)
916                     {
917                         using (currentUser.Impersonate())
918                         {
919                             return Task<Stream>.Factory.FromAsync(this.BeginGetRequestStream,
920                                 this.EndGetRequestStream, null);
921                         }
922                     }
923                 });
924             }
925             else
926             {
927                 return Task.Run(() => Task<Stream>.Factory.FromAsync(this.BeginGetRequestStream, 
928                     this.EndGetRequestStream, null));
929             }
930         }
931
932         // Offload to a different thread to avoid blocking the caller durring request submission.
933         [HostProtection(ExternalThreading = true)]
934         public virtual Task<WebResponse> GetResponseAsync()
935         {
936             IWebProxy proxy = null;
937             try { proxy = Proxy; }
938             catch (NotImplementedException) { }
939
940             // Preserve context for authentication
941             if (ExecutionContext.IsFlowSuppressed()
942                 && (UseDefaultCredentials || Credentials != null
943                     || (proxy != null && proxy.Credentials != null)))
944             {
945                 WindowsIdentity currentUser = SafeCaptureIdenity();
946
947                 // When flow is suppressed we would lose track of the current user across this thread switch.
948                 // Flow manually so that UseDefaultCredentials will work. BeginGetResponse will
949                 // take over from there.
950                 return Task.Run(() =>
951                 {
952                     using (currentUser)
953                     {
954                         using (currentUser.Impersonate())
955                         {
956                             return Task<WebResponse>.Factory.FromAsync(this.BeginGetResponse, 
957                                 this.EndGetResponse, null);
958                         }
959                     }
960                 });
961             }
962             else
963             {
964                 return Task.Run(() => Task<WebResponse>.Factory.FromAsync(this.BeginGetResponse, 
965                     this.EndGetResponse, null));
966             }
967         }
968
969         // Security: We need an assert for a call into WindowsIdentity.GetCurrent
970         [SecuritySafeCritical]
971         [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
972         [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Needed for identity flow.")]
973         private WindowsIdentity SafeCaptureIdenity()
974         {
975             return WindowsIdentity.GetCurrent();
976         }
977
978
979         /// <summary>
980         ///    <para>Aborts the Request</para>
981         /// </summary>
982         public virtual void Abort() {
983             throw ExceptionHelper.MethodNotImplementedException;
984         }
985
986         //
987         //
988         //
989         internal RequestCacheProtocol CacheProtocol
990         {
991             get
992             {
993                 return m_CacheProtocol;
994             }
995             set
996             {
997                 m_CacheProtocol = value;
998             }
999         }
1000
1001 #if !FEATURE_PAL
1002         //
1003         //
1004         //
1005         public AuthenticationLevel AuthenticationLevel {
1006             get {
1007                 return m_AuthenticationLevel;
1008             }
1009             set {
1010                 m_AuthenticationLevel = value;
1011             }
1012         }
1013
1014 #if !MONO
1015         // Methods to retrieve the context of the "reading phase" and of the "writing phase" of the request.
1016         // Each request type can define what goes into what phase.  Typically, the writing phase corresponds to
1017         // GetRequestStream() and the reading phase to GetResponse(), but if there's no request body, both phases
1018         // may happen inside GetResponse().
1019         //
1020         // Return null only on [....] (if we're on the [....] thread).  Otherwise throw if no context is available.
1021         internal virtual ContextAwareResult GetConnectingContext()
1022         {
1023             throw ExceptionHelper.MethodNotImplementedException;
1024         }
1025
1026         internal virtual ContextAwareResult GetWritingContext()
1027         {
1028             throw ExceptionHelper.MethodNotImplementedException;
1029         }
1030
1031         internal virtual ContextAwareResult GetReadingContext()
1032         {
1033             throw ExceptionHelper.MethodNotImplementedException;
1034         }
1035 #endif
1036
1037         //
1038         //
1039         //
1040         public TokenImpersonationLevel ImpersonationLevel {
1041             get {
1042                 return m_ImpersonationLevel;
1043             }
1044             set {
1045                 m_ImpersonationLevel = value;
1046             }
1047         }
1048 #endif  // !FEATURE_PAL
1049
1050         /// <summary>
1051         ///    <para>Provides an abstract way of having Async code callback into the request (saves a delegate)</para>
1052         /// </summary>
1053         internal virtual void RequestCallback(object obj) {
1054             throw ExceptionHelper.MethodNotImplementedException;
1055         }
1056
1057         //
1058         // Default Web Proxy implementation.
1059         //
1060         private static volatile IWebProxy s_DefaultWebProxy;
1061         private static volatile bool s_DefaultWebProxyInitialized;
1062
1063         internal static IWebProxy InternalDefaultWebProxy
1064         {
1065             get
1066             {
1067                 if (!s_DefaultWebProxyInitialized)
1068                 {
1069                     lock (InternalSyncObject)
1070                     {
1071                         if (!s_DefaultWebProxyInitialized)
1072                         {
1073                             GlobalLog.Print("WebRequest::get_InternalDefaultWebProxy(): Getting config.");
1074                             DefaultProxySectionInternal section = DefaultProxySectionInternal.GetSection();
1075                             if (section != null)
1076                             {
1077                                 s_DefaultWebProxy = section.WebProxy;
1078                             }
1079                             s_DefaultWebProxyInitialized = true;
1080                         }
1081                     }
1082                 }
1083                 return s_DefaultWebProxy;
1084             }
1085
1086             set
1087             {
1088                 // Same lock as above.  Avoid hitting config if the proxy is set first.
1089                 if (!s_DefaultWebProxyInitialized)
1090                 {
1091                     lock (InternalSyncObject)
1092                     {
1093                         s_DefaultWebProxy = value;
1094                         s_DefaultWebProxyInitialized = true;
1095                     }
1096                 }
1097                 else
1098                 {
1099                     s_DefaultWebProxy = value;
1100                 }
1101             }
1102         }
1103
1104         //
1105         // Get and set the global default proxy.  Use this instead of the old GlobalProxySelection.
1106         //
1107         public static IWebProxy DefaultWebProxy
1108         {
1109             get
1110             {
1111 #if !DISABLE_CAS_USE
1112                 ExceptionHelper.WebPermissionUnrestricted.Demand();
1113 #endif
1114                 return InternalDefaultWebProxy;
1115             }
1116
1117             set
1118             {
1119 #if !DISABLE_CAS_USE
1120                 ExceptionHelper.WebPermissionUnrestricted.Demand();
1121 #endif
1122                 InternalDefaultWebProxy = value;
1123             }
1124         }
1125
1126         //
1127         // This returns an "IE Proxy" based on the currently impersonated user's proxy settings.
1128         //
1129         public static IWebProxy GetSystemWebProxy()
1130         {
1131 #if !DISABLE_CAS_USE
1132             ExceptionHelper.WebPermissionUnrestricted.Demand();
1133 #endif
1134             return InternalGetSystemWebProxy();
1135         }
1136
1137         internal static IWebProxy InternalGetSystemWebProxy()
1138         {
1139 #if MONO
1140             // FIXME: Need to break mobile internal API
1141             return WebProxy.CreateDefaultProxy();
1142 #else
1143             return new WebProxyWrapperOpaque(new WebProxy(true));
1144 #endif
1145         }
1146
1147         //
1148         // To maintain backwards-compatibility, GlobalProxySelection.Select must return a proxy castable to WebProxy.
1149         // To get away from that restriction in the future, new APIs wrap the WebProxy in an internal wrapper.
1150         // Once Select is removed, the system-proxy functionality can be factored out of the WebProxy class.
1151         //
1152
1153         //
1154         // This doesn't expose the WebProxy.  It's used by GetSystemWebProxy(), which should never be castable to WebProxy.
1155         //
1156         internal class WebProxyWrapperOpaque : IAutoWebProxy
1157         {
1158             protected readonly WebProxy webProxy;
1159
1160             internal WebProxyWrapperOpaque(WebProxy webProxy)
1161             {
1162                 this.webProxy = webProxy;
1163             }
1164
1165             public Uri GetProxy(Uri destination)
1166             {
1167                 return webProxy.GetProxy(destination);
1168             }
1169
1170             public bool IsBypassed(Uri host)
1171             {
1172                 return webProxy.IsBypassed(host);
1173             }
1174
1175             public ICredentials Credentials
1176             {
1177                 get
1178                 {
1179                     return webProxy.Credentials;
1180                 }
1181
1182                 set
1183                 {
1184                     webProxy.Credentials = value;
1185                 }
1186             }
1187
1188             public ProxyChain GetProxies(Uri destination)
1189             {
1190                 return ((IAutoWebProxy) webProxy).GetProxies(destination);
1191             }
1192         }
1193
1194         //
1195         // Select returns the WebProxy out of this one.
1196         //
1197         internal class WebProxyWrapper : WebProxyWrapperOpaque
1198         {
1199             internal WebProxyWrapper(WebProxy webProxy) :
1200                 base(webProxy)
1201             { }
1202
1203             internal WebProxy WebProxy
1204             {
1205                 get
1206                 {
1207                     return webProxy;
1208                 }
1209             }
1210         }
1211
1212 #if !MONO
1213         //
1214         internal void SetupCacheProtocol(Uri uri)
1215         {
1216             m_CacheBinding = RequestCacheManager.GetBinding(uri.Scheme);
1217
1218             // Note if the cache is disabled it will give back a bypass policy.
1219             InternalSetCachePolicy( m_CacheBinding.Policy);
1220             if (m_CachePolicy == null)
1221             {
1222                 // If the protocol cache policy is not specifically configured, grab from the base class.
1223                 InternalSetCachePolicy(WebRequest.DefaultCachePolicy);
1224             }
1225         }
1226
1227         delegate void DelEtwFireBeginWRGet(object id, string uri, bool success, bool synchronous);
1228         delegate void DelEtwFireEndWRGet(object id, bool success, bool synchronous);
1229         delegate void DelEtwFireEndWRespGet(object id, bool success, bool synchronous, int statusCode);
1230         static DelEtwFireBeginWRGet s_EtwFireBeginGetResponse;
1231         static DelEtwFireEndWRespGet s_EtwFireEndGetResponse;
1232         static DelEtwFireBeginWRGet s_EtwFireBeginGetRequestStream;
1233         static DelEtwFireEndWRGet s_EtwFireEndGetRequestStream;
1234         static volatile bool s_TriedGetEtwDelegates;
1235
1236         private static void InitEtwMethods()
1237         {
1238             Type fest = typeof(FrameworkEventSource);
1239             var beginParamTypes = new Type[] { typeof(object), typeof(string), typeof(bool), typeof(bool) };
1240             var bindingFlags = BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public;
1241             var mi1 = fest.GetMethod("BeginGetResponse", bindingFlags, null, beginParamTypes, null);
1242             var mi2 = fest.GetMethod("EndGetResponse", bindingFlags, null, new Type[] { typeof(object), typeof(bool), typeof(bool), typeof(int) }, null);
1243             var mi3 = fest.GetMethod("BeginGetRequestStream", bindingFlags, null, beginParamTypes, null);
1244             var mi4 = fest.GetMethod("EndGetRequestStream", bindingFlags, null, new Type[] { typeof(object), typeof(bool), typeof(bool) }, null);
1245             if (mi1 != null && mi2 != null && mi3 != null && mi4 != null)
1246             {
1247                 s_EtwFireBeginGetResponse = (DelEtwFireBeginWRGet) mi1.CreateDelegate(typeof(DelEtwFireBeginWRGet), FrameworkEventSource.Log);
1248                 s_EtwFireEndGetResponse = (DelEtwFireEndWRespGet)mi2.CreateDelegate(typeof(DelEtwFireEndWRespGet), FrameworkEventSource.Log);
1249                 s_EtwFireBeginGetRequestStream = (DelEtwFireBeginWRGet) mi3.CreateDelegate(typeof(DelEtwFireBeginWRGet), FrameworkEventSource.Log);
1250                 s_EtwFireEndGetRequestStream = (DelEtwFireEndWRGet) mi4.CreateDelegate(typeof(DelEtwFireEndWRGet), FrameworkEventSource.Log);
1251             }
1252             s_TriedGetEtwDelegates = true;
1253         }
1254
1255         internal void LogBeginGetResponse(bool success, bool synchronous)
1256         {
1257             string uri = this.RequestUri.OriginalString;
1258             if (!s_TriedGetEtwDelegates) 
1259                 InitEtwMethods();
1260             if (s_EtwFireBeginGetResponse != null)
1261             {
1262                 s_EtwFireBeginGetResponse(this, uri, success, synchronous);
1263             }
1264         }
1265         internal void LogEndGetResponse(bool success, bool synchronous, int statusCode)
1266         {
1267             if (!s_TriedGetEtwDelegates) 
1268                 InitEtwMethods();
1269             if (s_EtwFireEndGetResponse != null) {
1270                 s_EtwFireEndGetResponse(this, success, synchronous, statusCode);
1271             }
1272         }
1273         internal void LogBeginGetRequestStream(bool success, bool synchronous)
1274         {
1275             string uri = this.RequestUri.OriginalString;
1276             if (!s_TriedGetEtwDelegates) 
1277                 InitEtwMethods();
1278             if (s_EtwFireBeginGetRequestStream != null)
1279             {
1280                 s_EtwFireBeginGetRequestStream(this, uri, success, synchronous);
1281             }
1282         }
1283         internal void LogEndGetRequestStream(bool success, bool synchronous)
1284         {
1285             if (!s_TriedGetEtwDelegates) 
1286                 InitEtwMethods();
1287             if (s_EtwFireEndGetRequestStream != null) {
1288
1289                 s_EtwFireEndGetRequestStream(this, success, synchronous);
1290             }
1291         }
1292 #endif
1293     } // class WebRequest
1294 } // namespace System.Net