Merge pull request #3028 from lateralusX/jlorenss/threadpool_warning
[mono.git] / mcs / class / referencesource / System / net / System / Net / Internal.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Internal.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net {
8     using System.IO;
9     using System.Reflection;
10     using System.Collections;
11     using System.Collections.Specialized;
12     using System.Globalization;
13     using System.Net.Sockets;
14     using System.Net.WebSockets;
15     using System.Runtime.InteropServices;
16     using System.Runtime.Versioning;
17     using System.Security.Authentication.ExtendedProtection;
18     using System.Security.Cryptography.X509Certificates;
19     using System.Security.Permissions;
20     using System.Diagnostics;
21     using System.Threading;
22     using System.Security;
23     using System.Net.Security;
24     using System.Net.NetworkInformation;
25     using System.Runtime.Serialization;
26     using Microsoft.Win32;
27
28     internal static class IntPtrHelper {
29         /*
30         // Consider removing.
31         internal static IntPtr Add(IntPtr a, IntPtr b) {
32             return (IntPtr) ((long)a + (long)b);
33         }
34         */
35         internal static IntPtr Add(IntPtr a, int b) {
36             return (IntPtr) ((long)a + (long)b);
37         }
38
39         internal static long Subtract(IntPtr a, IntPtr b) {
40             return ((long)a - (long)b);
41         }
42     }
43
44     internal class InternalException : SystemException
45     {
46         internal InternalException()
47         {
48             GlobalLog.Assert("InternalException thrown.");
49         }
50
51         internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) :
52             base(serializationInfo, streamingContext)
53         { }
54     }
55
56     internal static class NclUtilities
57     {
58         /// <devdoc>
59         ///    <para>
60         ///       Indicates true if the threadpool is low on threads,
61         ///       in this case we need to refuse to start new requests,
62         ///       and avoid blocking.
63         ///    </para>
64         /// </devdoc>
65         internal static bool IsThreadPoolLow()
66         {
67 #if !FEATURE_PAL
68             if (ComNetOS.IsAspNetServer)
69             {
70                 return false;
71             }
72 #endif //!FEATURE_PAL
73
74             int workerThreads, completionPortThreads;
75             ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
76
77 #if !FEATURE_PAL
78             return workerThreads < 2 || (completionPortThreads < 2);
79 #else
80             GlobalLog.Assert(completionPortThreads == 0, "completionPortThreads should be zero on the PAL");
81             return workerThreads < 2;
82 #endif //!FEATURE_PAL
83         }
84
85
86         internal static bool HasShutdownStarted
87         {
88             get
89             {
90                 return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload();
91             }
92         }
93
94         // This only works for context-destroying errors.
95         internal static bool IsCredentialFailure(SecurityStatus error)
96         {
97             return error == SecurityStatus.LogonDenied ||
98                 error == SecurityStatus.UnknownCredentials ||
99                 error == SecurityStatus.NoImpersonation ||
100                 error == SecurityStatus.NoAuthenticatingAuthority ||
101                 error == SecurityStatus.UntrustedRoot ||
102                 error == SecurityStatus.CertExpired ||
103                 error == SecurityStatus.SmartcardLogonRequired ||
104                 error == SecurityStatus.BadBinding;
105         }
106
107         // This only works for context-destroying errors.
108         internal static bool IsClientFault(SecurityStatus error)
109         {
110             return error == SecurityStatus.InvalidToken ||
111                 error == SecurityStatus.CannotPack ||
112                 error == SecurityStatus.QopNotSupported ||
113                 error == SecurityStatus.NoCredentials ||
114                 error == SecurityStatus.MessageAltered ||
115                 error == SecurityStatus.OutOfSequence ||
116                 error == SecurityStatus.IncompleteMessage ||
117                 error == SecurityStatus.IncompleteCredentials ||
118                 error == SecurityStatus.WrongPrincipal ||
119                 error == SecurityStatus.TimeSkew ||
120                 error == SecurityStatus.IllegalMessage ||
121                 error == SecurityStatus.CertUnknown ||
122                 error == SecurityStatus.AlgorithmMismatch ||
123                 error == SecurityStatus.SecurityQosFailed ||
124                 error == SecurityStatus.UnsupportedPreauth;
125         }
126
127
128         // ContextRelativeDemand
129         // Allows easily demanding a permission against a given ExecutionContext.
130         // Have requested the CLR to provide this method on ExecutionContext.
131         private static volatile ContextCallback s_ContextRelativeDemandCallback;
132
133         internal static ContextCallback ContextRelativeDemandCallback
134         {
135             get
136             {
137                 if (s_ContextRelativeDemandCallback == null)
138                     s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
139                 return s_ContextRelativeDemandCallback;
140             }
141         }
142
143         private static void DemandCallback(object state)
144         {
145             ((CodeAccessPermission) state).Demand();
146         }
147
148         // This is for checking if a hostname probably refers to this machine without going to DNS.
149         internal static bool GuessWhetherHostIsLoopback(string host)
150         {
151             string hostLower = host.ToLowerInvariant();
152             if (hostLower == "localhost" || hostLower == "loopback")
153             {
154                 return true;
155             }
156
157 #if !FEATURE_PAL
158             IPGlobalProperties ip = IPGlobalProperties.InternalGetIPGlobalProperties();
159             string hostnameLower = ip.HostName.ToLowerInvariant();
160             return hostLower == hostnameLower || hostLower == hostnameLower + "." + ip.DomainName.ToLowerInvariant();
161 #else
162             return false;
163 #endif
164         }
165
166         internal static bool IsFatal(Exception exception)
167         {
168             return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
169         }
170
171         // Need a fast cached list of local addresses for internal use.
172         private static volatile IPAddress[] _LocalAddresses;
173         private static object _LocalAddressesLock;
174
175 #if MONO_NOT_IMPLEMENTED
176 #if !FEATURE_PAL
177
178         private static volatile NetworkAddressChangePolled s_AddressChange;
179
180         internal static IPAddress[] LocalAddresses
181         {
182             get
183             {
184                 if (s_AddressChange != null && s_AddressChange.CheckAndReset())
185                 {
186                     return (_LocalAddresses = GetLocalAddresses());
187                 }
188
189                 if (_LocalAddresses != null)
190                 {
191                     return _LocalAddresses;
192                 }
193
194                 lock (LocalAddressesLock)
195                 {
196                     if (_LocalAddresses != null)
197                     {
198                         return _LocalAddresses;
199                     }
200
201                     s_AddressChange = new NetworkAddressChangePolled();
202
203                     return (_LocalAddresses = GetLocalAddresses());
204                 }
205             }
206         }
207
208         private static IPAddress[] GetLocalAddresses()
209         {
210             IPAddress[] local;
211
212             ArrayList collections = new ArrayList(16);
213             int total = 0;
214
215             SafeLocalFree buffer = null;
216             GetAdaptersAddressesFlags gaaFlags = GetAdaptersAddressesFlags.SkipAnycast | GetAdaptersAddressesFlags.SkipMulticast |
217                 GetAdaptersAddressesFlags.SkipFriendlyName | GetAdaptersAddressesFlags.SkipDnsServer;
218             uint size = 0;
219             uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, SafeLocalFree.Zero, ref size);
220             while (result == IpHelperErrors.ErrorBufferOverflow)
221             {
222                 try
223                 {
224                     buffer = SafeLocalFree.LocalAlloc((int)size);
225                     result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(AddressFamily.Unspecified, (uint)gaaFlags, IntPtr.Zero, buffer, ref size);
226
227                     if (result == IpHelperErrors.Success)
228                     {
229                         IntPtr nextAdapter = buffer.DangerousGetHandle();
230
231                         while (nextAdapter != IntPtr.Zero)
232                         {
233                             IpAdapterAddresses adapterAddresses = (IpAdapterAddresses)Marshal.PtrToStructure(
234                                 nextAdapter, typeof(IpAdapterAddresses));
235
236                             if (adapterAddresses.firstUnicastAddress != IntPtr.Zero)
237                             {
238                                 UnicastIPAddressInformationCollection coll = 
239                                     SystemUnicastIPAddressInformation.MarshalUnicastIpAddressInformationCollection(
240                                     adapterAddresses.firstUnicastAddress);
241                                 total += coll.Count;
242                                 collections.Add(coll);
243                             }
244
245                             nextAdapter = adapterAddresses.next;
246                         }
247                     }
248                 }
249                 finally
250                 {
251                     if (buffer != null)
252                         buffer.Close();
253                     buffer = null;
254                 }
255             }
256
257             if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData)
258             {
259                 throw new NetworkInformationException((int)result);
260             }
261
262             local = new IPAddress[total];
263             uint i = 0;
264             foreach (UnicastIPAddressInformationCollection coll in collections)
265             {
266                 foreach (IPAddressInformation info in coll)
267                 {
268                     local[i++] = info.Address;
269                 }
270             }
271             
272             return local;
273         }
274
275         internal static bool IsAddressLocal(IPAddress ipAddress) {
276             IPAddress[] localAddresses = NclUtilities.LocalAddresses;
277             for (int i = 0; i < localAddresses.Length; i++)
278             {
279                 if (ipAddress.Equals(localAddresses[i], false))
280                 {
281                     return true;
282                 }
283             }
284             return false;
285         }
286
287 #else // !FEATURE_PAL
288         private const int HostNameBufferLength = 256;
289         internal static string _LocalDomainName;
290
291         // Copied from the old version of DNS.cs
292         // Returns a list of our local addresses by calling gethostbyname with null.
293         //
294         private static IPHostEntry GetLocalHost()
295         {
296             //
297             // IPv6 Changes: If IPv6 is enabled, we can't simply use the
298             //               old IPv4 gethostbyname(null). Instead we need
299             //               to do a more complete lookup.
300             //
301             if (Socket.SupportsIPv6)
302             {
303                 //
304                 // IPv6 enabled: use getaddrinfo() of the local host name
305                 // to obtain this information. Need to get the machines
306                 // name as well - do that here so that we don't need to
307                 // Assert DNS permissions.
308                 //
309                 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
310                 SocketError errorCode =
311                     UnsafeNclNativeMethods.OSSOCK.gethostname(
312                     hostname,
313                     HostNameBufferLength);
314
315                 if (errorCode != SocketError.Success)
316                 {
317                     throw new SocketException();
318                 }
319
320                 return Dns.GetHostByName(hostname.ToString());
321             }
322             else
323             {
324                 //
325                 // IPv6 disabled: use gethostbyname() to obtain information.
326                 //
327                 IntPtr nativePointer =
328                     UnsafeNclNativeMethods.OSSOCK.gethostbyname(
329                     null);
330
331                 if (nativePointer == IntPtr.Zero)
332                 {
333                     throw new SocketException();
334                 }
335
336                 return Dns.NativeToHostEntry(nativePointer);
337             }
338
339         } // GetLocalHost
340
341         internal static IPAddress[] LocalAddresses
342         {
343             get
344             {
345                 IPAddress[] local = _LocalAddresses;
346                 if (local != null)
347                 {
348                     return local;
349                 }
350
351                 lock (LocalAddressesLock)
352                 {
353                     local = _LocalAddresses;
354                     if (local != null)
355                     {
356                         return local;
357                     }
358
359                     List<IPAddress> localList = new List<IPAddress>();
360
361                         try
362                         {
363                             IPHostEntry hostEntry = GetLocalHost();
364                             if (hostEntry != null)
365                             {
366                                 if (hostEntry.HostName != null)
367                                 {
368                                     int dot = hostEntry.HostName.IndexOf('.');
369                                     if (dot != -1)
370                                     {
371                                         _LocalDomainName = hostEntry.HostName.Substring(dot);
372                                     }
373                                 }
374
375                                 IPAddress[] ipAddresses = hostEntry.AddressList;
376                                 if (ipAddresses != null)
377                                 {
378                                     foreach (IPAddress ipAddress in ipAddresses)
379                                     {
380                                         localList.Add(ipAddress);
381                                     }
382                                 }
383                             }
384                         }
385                         catch
386                         {
387                         }
388
389                     local = new IPAddress[localList.Count];
390                     int index = 0;
391                     foreach (IPAddress ipAddress in localList)
392                     {
393                         local[index] = ipAddress;
394                         index++;
395                     }
396                     _LocalAddresses = local;
397
398                     return local;
399                 }
400             }
401         }
402 #endif // !FEATURE_PAL
403 #endif
404
405         private static object LocalAddressesLock
406         {
407             get
408             {
409                 if (_LocalAddressesLock == null)
410                 {
411                     Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
412                 }
413                 return _LocalAddressesLock;
414             }
415         }
416     }
417
418     internal static class NclConstants
419     {
420         internal static readonly object Sentinel = new object();
421         internal static readonly object[] EmptyObjectArray = new object[0];
422         internal static readonly Uri[] EmptyUriArray = new Uri[0];
423
424         internal static readonly byte[] CRLF = new byte[] {(byte) '\r', (byte) '\n'};
425         internal static readonly byte[] ChunkTerminator = new byte[] {(byte) '0', (byte) '\r', (byte) '\n', (byte) '\r', (byte) '\n'};
426     }
427     
428     //
429     // A simple [....] point, useful for deferring work.  Just an int value with helper methods.
430     // This is used by HttpWebRequest to syncronize Reads/Writes while waiting for a 100-Continue response.
431     //
432     internal struct InterlockedGate
433     {
434         private int m_State;
435
436         // Not currently waiting for a response
437         internal const int Open = 0;        // Initial state of gate.
438         // Starting the timer to wait for a response (async)
439         internal const int Triggering = 1;        // Gate is being actively held by a thread - indeterminate state.
440         // Waiting for response
441         internal const int Triggered = 2;   // The triggering event has occurred.
442         // Stopping the timer (got a response or timed out)
443         internal const int Signaling = 3;
444         // Got a response or timed out, may process the response.
445         internal const int Signaled = 4;
446         // Re/submitting data.
447         internal const int Completed = 5;      // The gated event is done.
448         
449 #if DEBUG
450         /* Consider removing
451         internal int State
452         {
453             get
454             {
455                 return m_State;
456             }
457         }
458         */
459 #endif
460         
461         // Only call when all threads are guaranteed to be done with the gate.
462         internal void Reset()
463         {
464             m_State = Open;
465         }
466
467         // Returns false if the gate is not taken.  If exclusive is true, throws if the gate is already triggered.
468         internal bool Trigger(bool exclusive)
469         {
470             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
471             if (exclusive && (gate == Triggering || gate == Triggered))
472             {
473                 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
474                 throw new InternalException();
475             }
476             return gate == Open;
477         }
478
479         // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation.  This is useful to set up an invariant
480         // that must be ready by the time another thread closes the gate.  Do not block between StartTrigger() and FinishTrigger(), just
481         // set up your state to be consistent.  If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
482         // it in a finally.
483         //
484         // Returns false if the gate is not taken.  If exclusive is true, throws if the gate is already triggering/ed.
485         internal bool StartTriggering(bool exclusive)
486         {
487             int gate = Interlocked.CompareExchange(ref m_State, Triggering, Open);
488             if (exclusive && (gate == Triggering || gate == Triggered))
489             {
490                 GlobalLog.Assert("InterlockedGate::StartTriggering", "Gate already triggered.");
491                 throw new InternalException();
492             }
493             return gate == Open;
494         }
495
496         // Gate must be held by StartTriggering().
497         internal void FinishTriggering()
498         {
499             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Triggering);
500             if (gate != Triggering)
501             {
502                 GlobalLog.Assert("InterlockedGate::FinishTriggering", "Gate not Triggering.");
503                 throw new InternalException();
504             }
505         }
506
507         // Use StartSignaling() and FinishSignaling() to signal the gate as a two step operation.  This is useful to 
508         // set up an invariant that must be ready by the time another thread closes the gate.  Do not block between 
509         // StartSignaling() and FinishSignaling(), just set up your state to be consistent.  If this method returns 
510         // true, FinishSignaling() *must* be called to avoid deadlock - do it in a finally.
511         //
512         // Returns false if the gate is not taken.  If exclusive is true, throws if the gate is already Signaling/ed.
513         internal bool StartSignaling(bool exclusive)
514         {
515             int gate = Interlocked.CompareExchange(ref m_State, Signaling, Triggered);
516             if (exclusive && (gate == Signaling || gate == Signaled)) // 
517             {
518                 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already Signaled.");
519                 throw new InternalException();
520             }
521             Debug.Assert(gate != Triggering, "Still Triggering");
522             return gate == Triggered;
523         }
524
525         // Gate must be held by StartSignaling().
526         internal void FinishSignaling()
527         {
528             int gate = Interlocked.CompareExchange(ref m_State, Signaled, Signaling);
529             if (gate != Signaling)
530             {
531                 GlobalLog.Assert("InterlockedGate::FinishSignaling", "Gate not Signaling; " + gate);
532                 throw new InternalException();
533             }
534         }
535             
536         // Makes sure only one thread completes the opperation.
537         internal bool Complete()
538         {
539             int gate = Interlocked.CompareExchange(ref m_State, Completed, Signaled);
540             Debug.Assert(gate != Signaling, "Still Signaling");
541             return (gate == Signaled);
542         }
543     }
544
545 #if !FEATURE_PAL
546     //
547     // A polling implementation of NetworkAddressChange.
548     //
549     internal class NetworkAddressChangePolled : IDisposable
550     {
551         private bool disposed;
552         private SafeCloseSocketAndEvent ipv4Socket = null;
553         private SafeCloseSocketAndEvent ipv6Socket = null;
554
555
556         internal unsafe NetworkAddressChangePolled()
557         {
558             Socket.InitializeSockets();
559             int blocking;
560             if (Socket.OSSupportsIPv4)
561             {
562                 blocking = -1;
563                 ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
564                 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv4Socket, IoctlSocketConstants.FIONBIO, ref blocking);
565             }
566
567             if(Socket.OSSupportsIPv6){
568                 blocking = -1;
569                 ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
570                 UnsafeNclNativeMethods.OSSOCK.ioctlsocket(ipv6Socket,IoctlSocketConstants.FIONBIO,ref blocking);
571             }
572             Setup(StartIPOptions.Both);
573         }
574
575         private unsafe void Setup(StartIPOptions startIPOptions)
576         {
577             int length;
578             SocketError errorCode;
579
580
581             if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0){
582                 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
583                     ipv4Socket.DangerousGetHandle(),
584                     (int) IOControlCode.AddressListChange,
585                     null, 0, null, 0,
586                     out length,
587                     SafeNativeOverlapped.Zero, IntPtr.Zero);
588
589                 if (errorCode != SocketError.Success) {
590                     NetworkInformationException exception = new NetworkInformationException();
591                     if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
592                         Dispose();
593                         return;
594                     }
595                 }
596
597                 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv4Socket, ipv4Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
598                 if (errorCode != SocketError.Success) {
599                     Dispose();
600                     return;
601                 }
602             }
603
604             if(Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) !=0){
605                 errorCode = (SocketError) UnsafeNclNativeMethods.OSSOCK.WSAIoctl_Blocking(
606                     ipv6Socket.DangerousGetHandle(),
607                     (int) IOControlCode.AddressListChange,
608                     null, 0, null, 0,
609                     out length,
610                     SafeNativeOverlapped.Zero, IntPtr.Zero);
611
612                 if (errorCode != SocketError.Success) {
613                     NetworkInformationException exception = new NetworkInformationException();
614                     if (exception.ErrorCode != (uint)SocketError.WouldBlock) {
615                         Dispose();
616                         return;
617                     }
618                 }
619
620                 errorCode = (SocketError)UnsafeNclNativeMethods.OSSOCK.WSAEventSelect(ipv6Socket, ipv6Socket.GetEventHandle().SafeWaitHandle, AsyncEventBits.FdAddressListChange);
621                 if (errorCode != SocketError.Success) {
622                     Dispose();
623                     return;
624                 }
625             }
626         }
627
628         internal bool CheckAndReset()
629         {
630             if(!disposed){
631                 lock (this){
632                     if (!disposed){
633                         StartIPOptions options = StartIPOptions.None;
634             
635                         if (ipv4Socket != null && ipv4Socket.GetEventHandle().WaitOne(0, false)){
636                             options|= StartIPOptions.StartIPv4;
637                         }
638                         if (ipv6Socket != null && ipv6Socket.GetEventHandle().WaitOne(0, false))
639                         {
640                             options|= StartIPOptions.StartIPv6;
641                         }
642             
643                         if(options != StartIPOptions.None){
644                             Setup(options);
645                             return true;
646                         }
647                     }
648                 }
649             }
650             return false;
651         }
652     
653         public void Dispose()
654         {
655             if(!disposed){
656                 lock (this){
657                     if (!disposed){
658                         if(ipv6Socket != null){
659                             ipv6Socket.Close();
660                             ipv6Socket = null;
661                         }
662                         if(ipv4Socket != null){
663                             ipv4Socket.Close();
664                             ipv6Socket = null;
665                         }
666                         disposed = true;
667                     }
668                 }
669             }
670         }
671     }
672 #endif // FEATURE_PAL
673
674
675
676 #if !FEATURE_PAL
677     internal static class ComNetOS
678     {
679         private const string OSInstallTypeRegKey = @"Software\Microsoft\Windows NT\CurrentVersion";
680         private const string OSInstallTypeRegKeyPath = @"HKEY_LOCAL_MACHINE\" + OSInstallTypeRegKey;
681         private const string OSInstallTypeRegName = "InstallationType";
682         private const string InstallTypeStringClient = "Client";
683         private const string InstallTypeStringServer = "Server";
684         private const string InstallTypeStringServerCore = "Server Core";
685         private const string InstallTypeStringEmbedded = "Embedded";
686
687         // Minimum support for Windows 2008 is assumed.
688         internal static readonly bool IsAspNetServer; // ie: running under ASP+
689         internal static readonly bool IsWin7orLater;  // Is Windows 7 or later
690         internal static readonly bool IsWin7Sp1orLater; // Is Windows 7 Sp1 or later (2008 R2 Sp1+)
691         internal static readonly bool IsWin8orLater;  // Is Windows 8 or later
692         internal static readonly WindowsInstallationType InstallationType; // e.g. Client, Server, Server Core
693
694         // We use it safe so assert
695         [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
696         [ResourceExposure(ResourceScope.None)]
697         [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
698         static ComNetOS()
699         {
700             OperatingSystem operatingSystem = Environment.OSVersion;
701
702             GlobalLog.Print("ComNetOS::.ctor(): " + operatingSystem.ToString());
703
704             Debug.Assert(operatingSystem.Platform != PlatformID.Win32Windows, "Windows 9x is not supported");
705
706             //
707             // Detect ASP+ as a platform running under NT
708             //
709
710             try
711             {
712                 IsAspNetServer = (Thread.GetDomain().GetData(".appDomain") != null);
713             }
714             catch { }
715             
716             IsWin7orLater = (operatingSystem.Version >= new Version(6, 1));
717
718             IsWin7Sp1orLater = (operatingSystem.Version >= new Version(6, 1, 7601));
719
720             IsWin8orLater = (operatingSystem.Version >= new Version(6, 2));
721
722             InstallationType = GetWindowsInstallType();
723             if (Logging.On) Logging.PrintInfo(Logging.Web, SR.GetString(SR.net_osinstalltype, InstallationType));
724         }
725
726         [RegistryPermission(SecurityAction.Assert, Read = OSInstallTypeRegKeyPath)]
727         private static WindowsInstallationType GetWindowsInstallType()
728         {
729             try
730             {
731                 using (RegistryKey installTypeKey = Registry.LocalMachine.OpenSubKey(OSInstallTypeRegKey))
732                 {
733                     string installType = installTypeKey.GetValue(OSInstallTypeRegName) as string;
734
735                     if (string.IsNullOrEmpty(installType))
736                     {
737                         if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_empty_osinstalltype, OSInstallTypeRegKey + "\\" + OSInstallTypeRegName));
738                         return WindowsInstallationType.Unknown;
739                     }
740                     else
741                     {
742                         if (String.Compare(installType, InstallTypeStringClient, StringComparison.OrdinalIgnoreCase) == 0)
743                         {
744                             return WindowsInstallationType.Client;
745                         }
746                         if (String.Compare(installType, InstallTypeStringServer, StringComparison.OrdinalIgnoreCase) == 0)
747                         {
748                             return WindowsInstallationType.Server;
749                         }
750                         if (String.Compare(installType, InstallTypeStringServerCore, StringComparison.OrdinalIgnoreCase) == 0)
751                         {
752                             return WindowsInstallationType.ServerCore;
753                         }
754                         if (String.Compare(installType, InstallTypeStringEmbedded, StringComparison.OrdinalIgnoreCase) == 0)
755                         {
756                             return WindowsInstallationType.Embedded;
757                         }
758
759                         if (Logging.On) Logging.PrintError(Logging.Web, SR.GetString(SR.net_unknown_osinstalltype, installType));
760
761                         // Our default return is unknown when we don't recognize the SKU or if the registry value 
762                         // doesn't exist. As a result, the SKU-specific checks in System.Net will not limit the set 
763                         // of functionality available. This allows SKUs we are not aware of to use all of our 
764                         // functionality. Burden is on them to ensure that all our dependencies are present. 
765                         // The alternative would be for us to throw an exception here. If we did this, these other 
766                         // SKUs wouldn't be able to load this code and test their behavior. We would need to update 
767                         // this code to enable them to run.
768                         return WindowsInstallationType.Unknown;
769                     }
770                 }
771             }
772             catch (UnauthorizedAccessException e)
773             {
774                 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
775                 return WindowsInstallationType.Unknown;
776             }
777             catch (SecurityException e)
778             {
779                 if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_cant_determine_osinstalltype, OSInstallTypeRegKey, e.Message));
780                 return WindowsInstallationType.Unknown;
781             }
782         }
783     }
784 #endif
785
786
787     //
788     // support class for Validation related stuff.
789     //
790     internal static class ValidationHelper {
791
792         public static string [] EmptyArray = new string[0];
793
794         internal static readonly char[]  InvalidMethodChars =
795                 new char[]{
796                 ' ',
797                 '\r',
798                 '\n',
799                 '\t'
800                 };
801
802         // invalid characters that cannot be found in a valid method-verb or http header
803         internal static readonly char[]  InvalidParamChars =
804                 new char[]{
805                 '(',
806                 ')',
807                 '<',
808                 '>',
809                 '@',
810                 ',',
811                 ';',
812                 ':',
813                 '\\',
814                 '"',
815                 '\'',
816                 '/',
817                 '[',
818                 ']',
819                 '?',
820                 '=',
821                 '{',
822                 '}',
823                 ' ',
824                 '\t',
825                 '\r',
826                 '\n'};
827
828         public static string [] MakeEmptyArrayNull(string [] stringArray) {
829             if ( stringArray == null || stringArray.Length == 0 ) {
830                 return null;
831             } else {
832                 return stringArray;
833             }
834         }
835
836         public static string MakeStringNull(string stringValue) {
837             if ( stringValue == null || stringValue.Length == 0) {
838                 return null;
839             } else {
840                 return stringValue;
841             }
842         }
843
844         /*
845         // Consider removing.
846         public static string MakeStringEmpty(string stringValue) {
847             if ( stringValue == null || stringValue.Length == 0) {
848                 return String.Empty;
849             } else {
850                 return stringValue;
851             }
852         }
853         */
854
855 #if TRAVE
856         /*
857         // Consider removing.
858         public static int HashCode(object objectValue) {
859             if (objectValue == null) {
860                 return -1;
861             } else {
862                 return objectValue.GetHashCode();
863             }
864         }
865         */
866 #endif
867
868         public static string ExceptionMessage(Exception exception) {
869             if (exception==null) {
870                 return string.Empty;
871             }
872             if (exception.InnerException==null) {
873                 return exception.Message;
874             }
875             return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
876         }
877
878         public static string ToString(object objectValue) {
879             if (objectValue == null) {
880                 return "(null)";
881             } else if (objectValue is string && ((string)objectValue).Length==0) {
882                 return "(string.empty)";
883             } else if (objectValue is Exception) {
884                 return ExceptionMessage(objectValue as Exception);
885             } else if (objectValue is IntPtr) {
886                 return "0x" + ((IntPtr)objectValue).ToString("x");
887             } else {
888                 return objectValue.ToString();
889             }
890         }
891         public static string HashString(object objectValue) {
892             if (objectValue == null) {
893                 return "(null)";
894             } else if (objectValue is string && ((string)objectValue).Length==0) {
895                 return "(string.empty)";
896             } else {
897                 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
898             }
899         }
900
901         public static bool IsInvalidHttpString(string stringValue) {
902             return stringValue.IndexOfAny(InvalidParamChars)!=-1;
903         }
904
905         public static bool IsBlankString(string stringValue) {
906             return stringValue==null || stringValue.Length==0;
907         }
908
909         /*
910         // Consider removing.
911         public static bool ValidateUInt32(long address) {
912             // on false, API should throw new ArgumentOutOfRangeException("address");
913             return address>=0x00000000 && address<=0xFFFFFFFF;
914         }
915         */
916
917         public static bool ValidateTcpPort(int port) {
918             // on false, API should throw new ArgumentOutOfRangeException("port");
919             return port>=IPEndPoint.MinPort && port<=IPEndPoint.MaxPort;
920         }
921
922         public static bool ValidateRange(int actual, int fromAllowed, int toAllowed) {
923             // on false, API should throw new ArgumentOutOfRangeException("argument");
924             return actual>=fromAllowed && actual<=toAllowed;
925         }
926
927         /*
928         // Consider removing.
929         public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
930             // on false, API should throw new ArgumentOutOfRangeException("argument");
931             return actual>=fromAllowed && actual<=toAllowed;
932         }
933         */
934
935         // There are threading tricks a malicious app can use to create an ArraySegment with mismatched 
936         // array/offset/count.  Copy locally and make sure they're valid before using them.
937         internal static void ValidateSegment(ArraySegment<byte> segment) {
938             if (segment == null || segment.Array == null) {
939                 throw new ArgumentNullException("segment");
940             }
941             // Length zero is explicitly allowed
942             if (segment.Offset < 0 || segment.Count < 0 
943                 || segment.Count > (segment.Array.Length - segment.Offset)) {
944                 throw new ArgumentOutOfRangeException("segment");
945             }
946         }
947     }
948
949     internal static class ExceptionHelper
950     {
951 #if !DISABLE_CAS_USE
952         internal static readonly KeyContainerPermission KeyContainerPermissionOpen = new KeyContainerPermission(KeyContainerPermissionFlags.Open);
953         internal static readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
954         internal static readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
955         internal static readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
956         internal static readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
957         internal static readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
958         internal static readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
959 #endif
960         internal static NotImplementedException MethodNotImplementedException {
961             get {
962                 return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException));
963             }
964         }
965
966         internal static NotImplementedException PropertyNotImplementedException {
967             get {
968                 return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException));
969             }
970         }
971
972         internal static NotSupportedException MethodNotSupportedException {
973             get {
974                 return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException));
975             }
976         }
977
978         internal static NotSupportedException PropertyNotSupportedException {
979             get {
980                 return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException));
981             }
982         }
983
984         internal static WebException IsolatedException {
985             get {
986                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
987             }
988         }
989
990         internal static WebException RequestAbortedException {
991             get {
992                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
993             }
994         }
995
996         internal static WebException CacheEntryNotFoundException {
997             get {
998                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
999             }
1000         }
1001
1002         internal static WebException RequestProhibitedByCachePolicyException {
1003             get {
1004                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1005             }
1006         }
1007     }
1008
1009     internal enum WindowsInstallationType
1010     { 
1011         Unknown = 0,
1012         Client,
1013         Server,
1014         ServerCore,
1015         Embedded
1016     }
1017
1018     internal enum SecurityStatus
1019     {
1020         // Success / Informational
1021         OK                          =   0x00000000,
1022         ContinueNeeded              =   unchecked((int)0x00090312),
1023         CompleteNeeded              =   unchecked((int)0x00090313),
1024         CompAndContinue             =   unchecked((int)0x00090314),
1025         ContextExpired              =   unchecked((int)0x00090317),
1026         CredentialsNeeded           =   unchecked((int)0x00090320),
1027         Renegotiate                 =   unchecked((int)0x00090321),
1028         
1029         // Errors
1030         OutOfMemory                 =   unchecked((int)0x80090300),
1031         InvalidHandle               =   unchecked((int)0x80090301),
1032         Unsupported                 =   unchecked((int)0x80090302),
1033         TargetUnknown               =   unchecked((int)0x80090303),
1034         InternalError               =   unchecked((int)0x80090304),
1035         PackageNotFound             =   unchecked((int)0x80090305),
1036         NotOwner                    =   unchecked((int)0x80090306),
1037         CannotInstall               =   unchecked((int)0x80090307),
1038         InvalidToken                =   unchecked((int)0x80090308),
1039         CannotPack                  =   unchecked((int)0x80090309),
1040         QopNotSupported             =   unchecked((int)0x8009030A),
1041         NoImpersonation             =   unchecked((int)0x8009030B),
1042         LogonDenied                 =   unchecked((int)0x8009030C),
1043         UnknownCredentials          =   unchecked((int)0x8009030D),
1044         NoCredentials               =   unchecked((int)0x8009030E),
1045         MessageAltered              =   unchecked((int)0x8009030F),
1046         OutOfSequence               =   unchecked((int)0x80090310),
1047         NoAuthenticatingAuthority   =   unchecked((int)0x80090311),
1048         IncompleteMessage           =   unchecked((int)0x80090318),
1049         IncompleteCredentials       =   unchecked((int)0x80090320),
1050         BufferNotEnough             =   unchecked((int)0x80090321),
1051         WrongPrincipal              =   unchecked((int)0x80090322),
1052         TimeSkew                    =   unchecked((int)0x80090324),
1053         UntrustedRoot               =   unchecked((int)0x80090325),
1054         IllegalMessage              =   unchecked((int)0x80090326),
1055         CertUnknown                 =   unchecked((int)0x80090327),
1056         CertExpired                 =   unchecked((int)0x80090328),
1057         AlgorithmMismatch           =   unchecked((int)0x80090331),
1058         SecurityQosFailed           =   unchecked((int)0x80090332),
1059         SmartcardLogonRequired      =   unchecked((int)0x8009033E),
1060         UnsupportedPreauth          =   unchecked((int)0x80090343),
1061         BadBinding                  =   unchecked((int)0x80090346)
1062     }
1063
1064     internal enum ContentTypeValues {
1065         ChangeCipherSpec    = 0x14,
1066         Alert               = 0x15,
1067         HandShake           = 0x16,
1068         AppData             = 0x17,
1069         Unrecognized        = 0xFF,
1070     }
1071
1072     internal enum ContextAttribute {
1073         //
1074         // look into <sspi.h> and <schannel.h>
1075         //
1076         Sizes               = 0x00,
1077         Names               = 0x01,
1078         Lifespan            = 0x02,
1079         DceInfo             = 0x03,
1080         StreamSizes         = 0x04,
1081         //KeyInfo             = 0x05, must not be used, see ConnectionInfo instead
1082         Authority           = 0x06,
1083         // SECPKG_ATTR_PROTO_INFO          = 7,
1084         // SECPKG_ATTR_PASSWORD_EXPIRY     = 8,
1085         // SECPKG_ATTR_SESSION_KEY         = 9,
1086         PackageInfo         = 0x0A,
1087         // SECPKG_ATTR_USER_FLAGS          = 11,
1088         NegotiationInfo    = 0x0C,
1089         // SECPKG_ATTR_NATIVE_NAMES        = 13,
1090         // SECPKG_ATTR_FLAGS               = 14,
1091         // SECPKG_ATTR_USE_VALIDATED       = 15,
1092         // SECPKG_ATTR_CREDENTIAL_NAME     = 16,
1093         // SECPKG_ATTR_TARGET_INFORMATION  = 17,
1094         // SECPKG_ATTR_ACCESS_TOKEN        = 18,
1095         // SECPKG_ATTR_TARGET              = 19,
1096         // SECPKG_ATTR_AUTHENTICATION_ID   = 20,
1097         UniqueBindings      = 0x19,
1098         EndpointBindings    = 0x1A,
1099         ClientSpecifiedSpn  = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27
1100         RemoteCertificate   = 0x53,
1101         LocalCertificate    = 0x54,
1102         RootStore           = 0x55,
1103         IssuerListInfoEx    = 0x59,
1104         ConnectionInfo      = 0x5A,
1105         // SECPKG_ATTR_EAP_KEY_BLOCK        0x5b   // returns SecPkgContext_EapKeyBlock  
1106         // SECPKG_ATTR_MAPPED_CRED_ATTR     0x5c   // returns SecPkgContext_MappedCredAttr  
1107         // SECPKG_ATTR_SESSION_INFO         0x5d   // returns SecPkgContext_SessionInfo  
1108         // SECPKG_ATTR_APP_DATA             0x5e   // sets/returns SecPkgContext_SessionAppData  
1109         // SECPKG_ATTR_REMOTE_CERTIFICATES  0x5F   // returns SecPkgContext_Certificates  
1110         // SECPKG_ATTR_CLIENT_CERT_POLICY   0x60   // sets    SecPkgCred_ClientCertCtlPolicy  
1111         // SECPKG_ATTR_CC_POLICY_RESULT     0x61   // returns SecPkgContext_ClientCertPolicyResult  
1112         // SECPKG_ATTR_USE_NCRYPT           0x62   // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group  
1113         // SECPKG_ATTR_LOCAL_CERT_INFO      0x63   // returns SecPkgContext_CertInfo  
1114         // SECPKG_ATTR_CIPHER_INFO          0x64   // returns new CNG SecPkgContext_CipherInfo  
1115         // SECPKG_ATTR_EAP_PRF_INFO         0x65   // sets    SecPkgContext_EapPrfInfo  
1116         // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66   // returns SecPkgContext_SupportedSignatures  
1117         // SECPKG_ATTR_REMOTE_CERT_CHAIN    0x67   // returns PCCERT_CONTEXT  
1118         UiInfo              = 0x68, // sets SEcPkgContext_UiInfo  
1119     }
1120
1121     internal enum Endianness {
1122         Network             = 0x00,
1123         Native              = 0x10,
1124     }
1125
1126     internal enum CredentialUse {
1127         Inbound             = 0x1,
1128         Outbound            = 0x2,
1129         Both                = 0x3,
1130     }
1131
1132     internal enum BufferType {
1133         Empty               = 0x00,
1134         Data                = 0x01,
1135         Token               = 0x02,
1136         Parameters          = 0x03,
1137         Missing             = 0x04,
1138         Extra               = 0x05,
1139         Trailer             = 0x06,
1140         Header              = 0x07,
1141         Padding             = 0x09,    // non-data padding
1142         Stream              = 0x0A,
1143         ChannelBindings     = 0x0E,
1144         TargetHost          = 0x10,
1145         ReadOnlyFlag        = unchecked((int)0x80000000),
1146         ReadOnlyWithChecksum= 0x10000000
1147     }
1148
1149     internal enum ChainPolicyType {
1150         Base                = 1,
1151         Authenticode        = 2,
1152         Authenticode_TS     = 3,
1153         SSL                 = 4,
1154         BasicConstraints    = 5,
1155         NtAuth              = 6,
1156     }
1157
1158     internal enum IgnoreCertProblem {
1159         not_time_valid              = 0x00000001,
1160         ctl_not_time_valid          = 0x00000002,
1161         not_time_nested             = 0x00000004,
1162         invalid_basic_constraints   = 0x00000008,
1163
1164         all_not_time_valid          =
1165             not_time_valid          |
1166             ctl_not_time_valid      |
1167             not_time_nested,
1168
1169         allow_unknown_ca            = 0x00000010,
1170         wrong_usage                 = 0x00000020,
1171         invalid_name                = 0x00000040,
1172         invalid_policy              = 0x00000080,
1173         end_rev_unknown             = 0x00000100,
1174         ctl_signer_rev_unknown      = 0x00000200,
1175         ca_rev_unknown              = 0x00000400,
1176         root_rev_unknown            = 0x00000800,
1177
1178         all_rev_unknown             =
1179             end_rev_unknown         |
1180             ctl_signer_rev_unknown  |
1181             ca_rev_unknown          |
1182             root_rev_unknown,
1183         none =
1184             not_time_valid |
1185             ctl_not_time_valid |
1186             not_time_nested |
1187             invalid_basic_constraints |
1188             allow_unknown_ca |
1189             wrong_usage |
1190             invalid_name |
1191             invalid_policy |
1192             end_rev_unknown |
1193             ctl_signer_rev_unknown |
1194             ca_rev_unknown |
1195             root_rev_unknown
1196     }
1197
1198     internal enum CertUsage {
1199         MatchTypeAnd    = 0x00,
1200         MatchTypeOr     = 0x01,
1201     }
1202
1203 #if !FEATURE_PAL
1204
1205     [StructLayout(LayoutKind.Sequential)]
1206     internal unsafe struct ChainPolicyParameter {
1207         public uint cbSize;
1208         public uint dwFlags;
1209         public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1210
1211         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1212     }
1213
1214     [StructLayout(LayoutKind.Sequential)]
1215     internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1216
1217         [StructLayout(LayoutKind.Explicit)]
1218         internal struct U {
1219               [FieldOffset(0)] internal uint cbStruct;  //DWORD
1220               [FieldOffset(0)] internal uint cbSize;    //DWORD
1221         };
1222         internal U u;
1223         internal int    dwAuthType;  //DWORD
1224         internal uint   fdwChecks;   //DWORD
1225         internal char*  pwszServerName; //WCHAR* // used to check against CN=xxxx
1226
1227         internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1228         {
1229             u.cbStruct = StructSize;
1230             u.cbSize   = StructSize;
1231             //#      define      AUTHTYPE_CLIENT         1
1232             //#      define      AUTHTYPE_SERVER         2
1233             dwAuthType = amIServer? 1: 2;
1234             fdwChecks = 0;
1235             pwszServerName = null;
1236         }
1237         static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1238     }
1239
1240     [StructLayout(LayoutKind.Sequential)]
1241     internal unsafe struct ChainPolicyStatus {
1242         public uint   cbSize;
1243         public uint   dwError;
1244         public uint   lChainIndex;
1245         public uint   lElementIndex;
1246         public void*  pvExtraPolicyStatus;
1247
1248         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1249     }
1250
1251     [StructLayout(LayoutKind.Sequential)]
1252     internal unsafe struct CertEnhKeyUse {
1253
1254         public uint   cUsageIdentifier;
1255         public void*  rgpszUsageIdentifier;
1256
1257 #if TRAVE
1258         public override string ToString() {
1259             return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1260         }
1261 #endif
1262     };
1263
1264     [StructLayout(LayoutKind.Sequential)]
1265     internal struct CertUsageMatch {
1266         public CertUsage     dwType;
1267         public CertEnhKeyUse Usage;
1268 #if TRAVE
1269         public override string ToString() {
1270             return "dwType="+dwType.ToString()+" "+Usage.ToString();
1271         }
1272 #endif
1273     };
1274
1275     [StructLayout(LayoutKind.Sequential)]
1276     internal struct ChainParameters {
1277         public uint cbSize;
1278         public CertUsageMatch RequestedUsage;
1279         public CertUsageMatch RequestedIssuancePolicy;
1280         public uint           UrlRetrievalTimeout;
1281         public int            BoolCheckRevocationFreshnessTime;
1282         public uint           RevocationFreshnessTime;
1283
1284
1285         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1286 #if TRAVE
1287         public override string ToString() {
1288             return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1289         }
1290 #endif
1291     };
1292
1293     [StructLayout(LayoutKind.Sequential)]
1294     struct _CERT_CHAIN_ELEMENT
1295     {
1296         public uint cbSize;
1297         public IntPtr pCertContext;
1298         // Since this structure is allocated by unmanaged code, we can
1299         // omit the fileds below since we don't need to access them
1300         // CERT_TRUST_STATUS   TrustStatus;
1301         // IntPtr                pRevocationInfo;
1302         // IntPtr                pIssuanceUsage;
1303         // IntPtr                pApplicationUsage;
1304     }
1305
1306     // CRYPTOAPI_BLOB
1307     //[StructLayout(LayoutKind.Sequential)]
1308     //unsafe struct CryptoBlob {
1309     //    // public uint cbData;
1310     //    // public byte* pbData;
1311     //    public uint dataSize;
1312     //    public byte* dataBlob;
1313     //}
1314
1315     // SecPkgContext_IssuerListInfoEx
1316     [StructLayout(LayoutKind.Sequential)]
1317     unsafe struct IssuerListInfoEx {
1318         public SafeHandle aIssuers;
1319         public uint cIssuers;
1320
1321         public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1322             aIssuers = handle;
1323             fixed(byte* voidPtr = nativeBuffer) {
1324                 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1325                 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1326             }
1327         }
1328     }
1329
1330
1331     [StructLayout(LayoutKind.Sequential)]
1332     internal struct SecureCredential {
1333
1334 /*
1335 typedef struct _SCHANNEL_CRED
1336 {
1337     DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION
1338     DWORD           cCreds;
1339     PCCERT_CONTEXT *paCred;
1340     HCERTSTORE      hRootStore;
1341
1342     DWORD           cMappers;
1343     struct _HMAPPER **aphMappers;
1344
1345     DWORD           cSupportedAlgs;
1346     ALG_ID *        palgSupportedAlgs;
1347
1348     DWORD           grbitEnabledProtocols;
1349     DWORD           dwMinimumCipherStrength;
1350     DWORD           dwMaximumCipherStrength;
1351     DWORD           dwSessionLifespan;
1352     DWORD           dwFlags;
1353     DWORD           reserved;
1354 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1355 */
1356
1357         public const int CurrentVersion = 0x4;
1358
1359         public int version;
1360         public int cCreds;
1361
1362         // ptr to an array of pointers
1363         // There is a hack done with this field.  AcquireCredentialsHandle requires an array of
1364         // certificate handles; we only ever use one.  In order to avoid pinning a one element array,
1365         // we copy this value onto the stack, create a pointer on the stack to the copied value,
1366         // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
1367         // Then we fix it up afterwards.  Fine as long as all the SSPI credentials are not
1368         // supposed to be threadsafe.
1369         public IntPtr certContextArray;
1370
1371         private readonly IntPtr rootStore;               // == always null, OTHERWISE NOT RELIABLE
1372         public int cMappers;
1373         private readonly IntPtr phMappers;               // == always null, OTHERWISE NOT RELIABLE
1374         public int cSupportedAlgs;
1375         private readonly IntPtr palgSupportedAlgs;       // == always null, OTHERWISE NOT RELIABLE
1376         public SchProtocols grbitEnabledProtocols;
1377         public int dwMinimumCipherStrength;
1378         public int dwMaximumCipherStrength;
1379         public int dwSessionLifespan;
1380         public SecureCredential.Flags dwFlags;
1381         public int reserved;
1382
1383         [Flags]
1384         public enum Flags {
1385             Zero            = 0,
1386             NoSystemMapper  = 0x02,
1387             NoNameCheck     = 0x04,
1388             ValidateManual  = 0x08,
1389             NoDefaultCred   = 0x10,
1390             ValidateAuto    = 0x20,
1391             UseStrongCrypto = 0x00400000,
1392         }
1393
1394         public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
1395             // default values required for a struct
1396             rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
1397             cCreds = cMappers = cSupportedAlgs = 0;
1398
1399             if (policy == EncryptionPolicy.RequireEncryption) {
1400                 // Prohibit null encryption cipher
1401                 dwMinimumCipherStrength = 0;
1402                 dwMaximumCipherStrength = 0;
1403             }
1404             else if (policy == EncryptionPolicy.AllowNoEncryption) {
1405                 // Allow null encryption cipher in addition to other ciphers
1406                 dwMinimumCipherStrength = -1;
1407                 dwMaximumCipherStrength =  0;
1408             }
1409             else if (policy == EncryptionPolicy.NoEncryption) {
1410                 // Suppress all encryption and require null encryption cipher only
1411                 dwMinimumCipherStrength = -1;
1412                 dwMaximumCipherStrength = -1;
1413             }
1414             else {
1415                 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1416             }
1417             
1418             dwSessionLifespan = reserved = 0;
1419             this.version = version;
1420             dwFlags = flags;
1421             grbitEnabledProtocols = protocols;
1422             if (certificate != null) {
1423                 certContextArray = certificate.Handle;
1424                 cCreds = 1;
1425             }
1426         }
1427
1428         [System.Diagnostics.Conditional("TRAVE")]
1429         internal void DebugDump() {
1430             GlobalLog.Print("SecureCredential #"+GetHashCode());
1431             GlobalLog.Print("    version                 = " + version);
1432             GlobalLog.Print("    cCreds                  = " + cCreds);
1433             GlobalLog.Print("    certContextArray        = " + String.Format("0x{0:x}", certContextArray));
1434             GlobalLog.Print("    rootStore               = " + String.Format("0x{0:x}", rootStore));
1435             GlobalLog.Print("    cMappers                = " + cMappers);
1436             GlobalLog.Print("    phMappers               = " + String.Format("0x{0:x}", phMappers));
1437             GlobalLog.Print("    cSupportedAlgs          = " + cSupportedAlgs);
1438             GlobalLog.Print("    palgSupportedAlgs       = " + String.Format("0x{0:x}", palgSupportedAlgs));
1439             GlobalLog.Print("    grbitEnabledProtocols   = " + String.Format("0x{0:x}", grbitEnabledProtocols));
1440             GlobalLog.Print("    dwMinimumCipherStrength = " + dwMinimumCipherStrength);
1441             GlobalLog.Print("    dwMaximumCipherStrength = " + dwMaximumCipherStrength);
1442             GlobalLog.Print("    dwSessionLifespan       = " + String.Format("0x{0:x}", dwSessionLifespan));
1443             GlobalLog.Print("    dwFlags                 = " + String.Format("0x{0:x}", dwFlags));
1444             GlobalLog.Print("    reserved                = " + String.Format("0x{0:x}", reserved));
1445         }
1446
1447     } // SecureCredential
1448
1449 #endif // !FEATURE_PAL
1450
1451     [StructLayout(LayoutKind.Sequential)]
1452     internal unsafe struct SecurityBufferStruct {
1453         public int          count;
1454         public BufferType   type;
1455         public IntPtr       token;
1456
1457         public static readonly int Size = sizeof(SecurityBufferStruct);
1458     }
1459
1460     internal class SecurityBuffer {
1461         public int size;
1462         public BufferType type;
1463         public byte[] token;
1464         public SafeHandle unmanagedToken;
1465         public int offset;
1466
1467         public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
1468             GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range.  [" + offset + "]");
1469             GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range.  [" + size + "]");
1470                         
1471             this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
1472             this.size   = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
1473             this.type   = tokentype;
1474             this.token  = size == 0 ? null : data;
1475         }
1476
1477         public SecurityBuffer(byte[] data, BufferType tokentype) {
1478             this.size   = data == null ? 0 : data.Length;
1479             this.type   = tokentype;
1480             this.token  = size == 0 ? null : data;
1481         }
1482
1483         public SecurityBuffer(int size, BufferType tokentype) {
1484             GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range.  [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1485
1486             this.size   = size;
1487             this.type   = tokentype;
1488             this.token  = size == 0 ? null : new byte[size];
1489         }
1490
1491         public SecurityBuffer(ChannelBinding binding) {
1492             this.size           = (binding == null ? 0 : binding.Size);
1493             this.type           = BufferType.ChannelBindings;
1494             this.unmanagedToken = binding;
1495         }
1496     }
1497
1498     [StructLayout(LayoutKind.Sequential)]
1499     internal unsafe class SecurityBufferDescriptor {
1500     /*
1501     typedef struct _SecBufferDesc {
1502         ULONG        ulVersion;
1503         ULONG        cBuffers;
1504         PSecBuffer   pBuffers;
1505     } SecBufferDesc, * PSecBufferDesc;
1506     */
1507             public  readonly    int     Version;
1508             public  readonly    int     Count;
1509             public  void*       UnmanagedPointer;
1510
1511         public SecurityBufferDescriptor(int count) {
1512             Version = 0;
1513             Count = count;
1514             UnmanagedPointer = null;
1515         }
1516
1517         [System.Diagnostics.Conditional("TRAVE")]
1518         internal void DebugDump() {
1519             GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
1520             GlobalLog.Print("    version             = " + Version);
1521             GlobalLog.Print("    count               = " + Count);
1522             GlobalLog.Print("    securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x"));
1523         }
1524     } // SecurityBufferDescriptor
1525
1526     internal  enum    CertificateEncoding {
1527         Zero                     = 0,
1528         X509AsnEncoding          = unchecked((int)0x00000001),
1529         X509NdrEncoding          = unchecked((int)0x00000002),
1530         Pkcs7AsnEncoding         = unchecked((int)0x00010000),
1531         Pkcs7NdrEncoding         = unchecked((int)0x00020000),
1532         AnyAsnEncoding           = X509AsnEncoding|Pkcs7AsnEncoding
1533     }
1534
1535     internal  enum    CertificateProblem {
1536         OK                          =   0x00000000,
1537         TrustNOSIGNATURE            = unchecked((int)0x800B0100),
1538         CertEXPIRED                 = unchecked((int)0x800B0101),
1539         CertVALIDITYPERIODNESTING   = unchecked((int)0x800B0102),
1540         CertROLE                    = unchecked((int)0x800B0103),
1541         CertPATHLENCONST            = unchecked((int)0x800B0104),
1542         CertCRITICAL                = unchecked((int)0x800B0105),
1543         CertPURPOSE                 = unchecked((int)0x800B0106),
1544         CertISSUERCHAINING          = unchecked((int)0x800B0107),
1545         CertMALFORMED               = unchecked((int)0x800B0108),
1546         CertUNTRUSTEDROOT           = unchecked((int)0x800B0109),
1547         CertCHAINING                = unchecked((int)0x800B010A),
1548         CertREVOKED                 = unchecked((int)0x800B010C),
1549         CertUNTRUSTEDTESTROOT       = unchecked((int)0x800B010D),
1550         CertREVOCATION_FAILURE      = unchecked((int)0x800B010E),
1551         CertCN_NO_MATCH             = unchecked((int)0x800B010F),
1552         CertWRONG_USAGE             = unchecked((int)0x800B0110),
1553         TrustEXPLICITDISTRUST       = unchecked((int)0x800B0111),
1554         CertUNTRUSTEDCA             = unchecked((int)0x800B0112),
1555         CertINVALIDPOLICY           = unchecked((int)0x800B0113),
1556         CertINVALIDNAME             = unchecked((int)0x800B0114),
1557
1558         CryptNOREVOCATIONCHECK       = unchecked((int)0x80092012),
1559         CryptREVOCATIONOFFLINE       = unchecked((int)0x80092013),
1560
1561         TrustSYSTEMERROR            = unchecked((int)0x80096001),
1562         TrustNOSIGNERCERT           = unchecked((int)0x80096002),
1563         TrustCOUNTERSIGNER          = unchecked((int)0x80096003),
1564         TrustCERTSIGNATURE          = unchecked((int)0x80096004),
1565         TrustTIMESTAMP              = unchecked((int)0x80096005),
1566         TrustBADDIGEST              = unchecked((int)0x80096010),
1567         TrustBASICCONSTRAINTS       = unchecked((int)0x80096019),
1568         TrustFINANCIALCRITERIA      = unchecked((int)0x8009601E),
1569     }
1570
1571     [StructLayout(LayoutKind.Sequential)]
1572     internal class SecChannelBindings
1573     {
1574         internal int dwInitiatorAddrType;
1575         internal int cbInitiatorLength;
1576         internal int dwInitiatorOffset;
1577
1578         internal int dwAcceptorAddrType;
1579         internal int cbAcceptorLength;
1580         internal int dwAcceptorOffset;
1581
1582         internal int cbApplicationDataLength;
1583         internal int dwApplicationDataOffset;
1584     }
1585
1586     //
1587     // WebRequestPrefixElement
1588     //
1589     // This is an element of the prefix list. It contains the prefix and the
1590     // interface to be called to create a request for that prefix.
1591     //
1592
1593     /// <devdoc>
1594     ///    <para>[To be supplied.]</para>
1595     /// </devdoc>
1596     // internal class WebRequestPrefixElement {
1597     internal class WebRequestPrefixElement  {
1598
1599         /// <devdoc>
1600         ///    <para>[To be supplied.]</para>
1601         /// </devdoc>
1602         public    string              Prefix;
1603         /// <devdoc>
1604         ///    <para>[To be supplied.]</para>
1605         /// </devdoc>
1606         internal    IWebRequestCreate   creator;
1607         /// <devdoc>
1608         ///    <para>[To be supplied.]</para>
1609         /// </devdoc>
1610         internal    Type   creatorType;
1611
1612         public IWebRequestCreate Creator {
1613             get {
1614                 if (creator == null && creatorType != null) {
1615                     lock(this) {
1616                         if (creator == null) {
1617                             creator = (IWebRequestCreate)Activator.CreateInstance(
1618                                                         creatorType,
1619                                                         BindingFlags.CreateInstance
1620                                                         | BindingFlags.Instance
1621                                                         | BindingFlags.NonPublic
1622                                                         | BindingFlags.Public,
1623                                                         null,          // Binder
1624                                                         new object[0], // no arguments
1625                                                         CultureInfo.InvariantCulture
1626                                                         );
1627                         }
1628                     }
1629                 }
1630
1631                 return creator;
1632             }
1633
1634             set {
1635                 creator = value;
1636             }
1637         }
1638
1639         public WebRequestPrefixElement(string P, Type creatorType) {
1640             // verify that its of the proper type of IWebRequestCreate
1641             if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1642             {
1643                 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1644                                                                 creatorType.AssemblyQualifiedName,
1645                                                                 "IWebRequestCreate"));
1646             }
1647
1648             Prefix = P;
1649             this.creatorType = creatorType;
1650         }
1651
1652         /// <devdoc>
1653         ///    <para>[To be supplied.]</para>
1654         /// </devdoc>
1655         public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1656             Prefix = P;
1657             Creator = C;
1658         }
1659
1660     } // class PrefixListElement
1661
1662
1663 #if MONO_FEATURE_WEB_STACK
1664
1665     //
1666     // HttpRequestCreator.
1667     //
1668     // This is the class that we use to create HTTP and HTTPS requests.
1669     //
1670
1671     internal class HttpRequestCreator : IWebRequestCreate {
1672
1673         /*++
1674
1675          Create - Create an HttpWebRequest.
1676
1677             This is our method to create an HttpWebRequest. We register
1678             for HTTP and HTTPS Uris, and this method is called when a request
1679             needs to be created for one of those.
1680
1681
1682             Input:
1683                     Uri             - Uri for request being created.
1684
1685             Returns:
1686                     The newly created HttpWebRequest.
1687
1688          --*/
1689
1690         public WebRequest Create( Uri Uri ) {
1691             //
1692             // Note, DNS permissions check will not happen on WebRequest
1693             //
1694             return new HttpWebRequest(Uri, null);
1695         }
1696
1697     } // class HttpRequestCreator
1698
1699     //
1700     // WebSocketHttpRequestCreator.
1701     //
1702     // This is the class that we use to create WebSocket connection requests.
1703     //
1704
1705     internal class WebSocketHttpRequestCreator : IWebRequestCreate
1706     {
1707         private string m_httpScheme;
1708
1709         // This ctor is used to create a WebSocketHttpRequestCreator.
1710         // We will do a URI change to update the scheme with Http or Https scheme. The usingHttps boolean is 
1711         // used to indicate whether the created HttpWebRequest should take the https scheme or not.
1712         public WebSocketHttpRequestCreator(bool usingHttps)
1713         {
1714             m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1715         }
1716
1717         /*++
1718
1719          Create - Create an HttpWebRequest.
1720
1721             This is our method to create an HttpWebRequest for WebSocket connection. We register
1722             We will register it for custom Uri prefixes. And this method is called when a request
1723             needs to be created for one of those. The created HttpWebRequest will still be with Http or Https
1724             scheme, depending on the m_httpScheme field of this object.
1725
1726
1727             Input:
1728                     Uri             - Uri for request being created.
1729
1730             Returns:
1731                     The newly created HttpWebRequest for WebSocket connection.
1732
1733          --*/
1734
1735         public WebRequest Create(Uri Uri)
1736         {
1737             UriBuilder uriBuilder = new UriBuilder(Uri);
1738             uriBuilder.Scheme = m_httpScheme;
1739             HttpWebRequest request = new HttpWebRequest(uriBuilder.Uri, null, true, "WebSocket" + Guid.NewGuid());
1740             WebSocketHelpers.PrepareWebRequest(ref request);
1741             return request;
1742         }
1743
1744     } // class WebSocketHttpRequestCreator
1745
1746
1747
1748
1749     //
1750     //  CoreResponseData - Used to store result of HTTP header parsing and
1751     //      response parsing.  Also Contains new stream to use, and
1752     //      is used as core of new Response
1753     //
1754     internal class CoreResponseData {
1755
1756         // Status Line Response Values
1757         public HttpStatusCode m_StatusCode;
1758         public string m_StatusDescription;
1759         public bool m_IsVersionHttp11;
1760
1761         // Content Length needed for semantics, -1 if chunked
1762         public long m_ContentLength;
1763
1764         // Response Headers
1765         public WebHeaderCollection m_ResponseHeaders;
1766
1767         // ConnectStream - for reading actual data
1768         public Stream m_ConnectStream;
1769
1770         internal CoreResponseData Clone() {
1771             CoreResponseData cloneResponseData = new CoreResponseData();
1772             cloneResponseData.m_StatusCode        = m_StatusCode;
1773             cloneResponseData.m_StatusDescription = m_StatusDescription;
1774             cloneResponseData.m_IsVersionHttp11   = m_IsVersionHttp11;
1775             cloneResponseData.m_ContentLength     = m_ContentLength;
1776             cloneResponseData.m_ResponseHeaders   = m_ResponseHeaders;
1777             cloneResponseData.m_ConnectStream     = m_ConnectStream;
1778             return cloneResponseData;
1779         }
1780
1781     }
1782 #endif
1783
1784
1785     internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1786
1787     //
1788     // this class contains known header names
1789     //
1790
1791     internal static class HttpKnownHeaderNames {
1792
1793         public const string CacheControl = "Cache-Control";
1794         public const string Connection = "Connection";
1795         public const string Date = "Date";
1796         public const string KeepAlive = "Keep-Alive";
1797         public const string Pragma = "Pragma";
1798         public const string ProxyConnection = "Proxy-Connection";
1799         public const string Trailer = "Trailer";
1800         public const string TransferEncoding = "Transfer-Encoding";
1801         public const string Upgrade = "Upgrade";
1802         public const string Via = "Via";
1803         public const string Warning = "Warning";
1804         public const string ContentLength = "Content-Length";
1805         public const string ContentType = "Content-Type";
1806         public const string ContentDisposition = "Content-Disposition";
1807         public const string ContentEncoding = "Content-Encoding";
1808         public const string ContentLanguage = "Content-Language";
1809         public const string ContentLocation = "Content-Location";
1810         public const string ContentRange = "Content-Range";
1811         public const string Expires = "Expires";
1812         public const string LastModified = "Last-Modified";
1813         public const string Age = "Age";
1814         public const string Location = "Location";
1815         public const string ProxyAuthenticate = "Proxy-Authenticate";
1816         public const string RetryAfter = "Retry-After";
1817         public const string Server = "Server";
1818         public const string SetCookie = "Set-Cookie";
1819         public const string SetCookie2 = "Set-Cookie2";
1820         public const string Vary = "Vary";
1821         public const string WWWAuthenticate = "WWW-Authenticate";
1822         public const string Accept = "Accept";
1823         public const string AcceptCharset = "Accept-Charset";
1824         public const string AcceptEncoding = "Accept-Encoding";
1825         public const string AcceptLanguage = "Accept-Language";
1826         public const string Authorization = "Authorization";
1827         public const string Cookie = "Cookie";
1828         public const string Cookie2 = "Cookie2";
1829         public const string Expect = "Expect";
1830         public const string From = "From";
1831         public const string Host = "Host";
1832         public const string IfMatch = "If-Match";
1833         public const string IfModifiedSince = "If-Modified-Since";
1834         public const string IfNoneMatch = "If-None-Match";
1835         public const string IfRange = "If-Range";
1836         public const string IfUnmodifiedSince = "If-Unmodified-Since";
1837         public const string MaxForwards = "Max-Forwards";
1838         public const string ProxyAuthorization = "Proxy-Authorization";
1839         public const string Referer = "Referer";
1840         public const string Range = "Range";
1841         public const string UserAgent = "User-Agent";
1842         public const string ContentMD5 = "Content-MD5";
1843         public const string ETag = "ETag";
1844         public const string TE = "TE";
1845         public const string Allow = "Allow";
1846         public const string AcceptRanges = "Accept-Ranges";
1847         public const string P3P = "P3P";
1848         public const string XPoweredBy = "X-Powered-By";
1849         public const string XAspNetVersion = "X-AspNet-Version";
1850         public const string SecWebSocketKey = "Sec-WebSocket-Key";
1851         public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
1852         public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
1853         public const string Origin = "Origin";
1854         public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
1855         public const string SecWebSocketVersion = "Sec-WebSocket-Version"; 
1856     }
1857
1858     /// <devdoc>
1859     ///    <para>
1860     ///       Represents the method that will notify callers when a continue has been
1861     ///       received by the client.
1862     ///    </para>
1863     /// </devdoc>
1864     // Delegate type for us to notify callers when we receive a continue
1865     public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1866
1867     //
1868     // HttpWriteMode - used to control the way in which an entity Body is posted.
1869     //
1870     enum HttpWriteMode {
1871         Unknown         = 0,
1872         ContentLength   = 1,
1873         Chunked         = 2,
1874         Buffer          = 3,
1875         None            = 4,
1876     }
1877
1878     // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1879     delegate void UnlockConnectionDelegate();
1880
1881     enum HttpBehaviour : byte {
1882         Unknown                     = 0,
1883         HTTP10                      = 1,
1884         HTTP11PartiallyCompliant    = 2,
1885         HTTP11                      = 3,
1886     }
1887
1888     internal enum HttpProcessingResult {
1889         Continue  = 0,
1890         ReadWait  = 1,
1891         WriteWait = 2,
1892     }
1893
1894     //
1895     // HttpVerb - used to define various per Verb Properties
1896     //
1897
1898     //
1899     // Note - this is a place holder for Verb properties,
1900     //  the following two bools can most likely be combined into
1901     //  a single Enum type.  And the Verb can be incorporated.
1902     //
1903     class KnownHttpVerb {
1904         internal string Name; // verb name
1905
1906         internal bool RequireContentBody; // require content body to be sent
1907         internal bool ContentBodyNotAllowed; // not allowed to send content body
1908         internal bool ConnectRequest; // special semantics for a connect request
1909         internal bool ExpectNoContentResponse; // response will not have content body
1910
1911         internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1912             Name = name;
1913             RequireContentBody = requireContentBody;
1914             ContentBodyNotAllowed = contentBodyNotAllowed;
1915             ConnectRequest = connectRequest;
1916             ExpectNoContentResponse = expectNoContentResponse;
1917         }
1918
1919         // Force an an init, before we use them
1920         private static ListDictionary NamedHeaders;
1921
1922         // known verbs
1923         internal static KnownHttpVerb Get;
1924         internal static KnownHttpVerb Connect;
1925         internal static KnownHttpVerb Head;
1926         internal static KnownHttpVerb Put;
1927         internal static KnownHttpVerb Post;
1928         internal static KnownHttpVerb MkCol;
1929
1930         //
1931         // InitializeKnownVerbs - Does basic init for this object,
1932         //  such as creating defaultings and filling them
1933         //
1934         static KnownHttpVerb() {
1935             NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
1936             Get = new KnownHttpVerb("GET", false, true, false, false);
1937             Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
1938             Head = new KnownHttpVerb("HEAD", false, true, false, true);
1939             Put = new KnownHttpVerb("PUT", true, false, false, false);
1940             Post = new KnownHttpVerb("POST", true, false, false, false);
1941             MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
1942             NamedHeaders[Get.Name] = Get;
1943             NamedHeaders[Connect.Name] = Connect;
1944             NamedHeaders[Head.Name] = Head;
1945             NamedHeaders[Put.Name] = Put;
1946             NamedHeaders[Post.Name] = Post;
1947             NamedHeaders[MkCol.Name] = MkCol;
1948         }
1949
1950         public bool Equals(KnownHttpVerb verb) {
1951             return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1952         }
1953
1954         public static KnownHttpVerb Parse(string name) {
1955             KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
1956             if (knownHttpVerb==null) {
1957                 // unknown verb, default behaviour
1958                 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
1959             }
1960             return knownHttpVerb;
1961         }
1962     }
1963
1964     //
1965     // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1966     //
1967
1968     internal class HttpProtocolUtils {
1969
1970         private HttpProtocolUtils() {
1971         }
1972
1973         //
1974         // extra buffers for build/parsing, recv/send HTTP data,
1975         //  at some point we should consolidate
1976         //
1977
1978
1979         // parse String to DateTime format.
1980         internal static DateTime string2date(String S) {
1981             DateTime dtOut;
1982             if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
1983                 return dtOut;
1984             }
1985             else {
1986                 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
1987             }
1988
1989         }
1990
1991         // convert Date to String using RFC 1123 pattern
1992         internal static string date2string(DateTime D) {
1993             DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
1994             return D.ToUniversalTime().ToString("R", dateFormat);
1995         }
1996     }
1997
1998 #if !FEATURE_PAL
1999     // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider
2000     internal class  PolicyWrapper {
2001         private const uint          IgnoreUnmatchedCN       = 0x00001000;
2002         private ICertificatePolicy  fwdPolicy;
2003         private ServicePoint        srvPoint;
2004         private WebRequest          request;
2005
2006         internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2007             this.fwdPolicy = policy;
2008             srvPoint = sp;
2009             request = wr;
2010         }
2011
2012         public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2013             return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2014         }
2015
2016         internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
2017             GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags));
2018             ChainPolicyStatus status = new ChainPolicyStatus();
2019             status.cbSize = ChainPolicyStatus.StructSize;
2020             int errorCode =
2021                 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2022                     (IntPtr) ChainPolicyType.SSL,
2023                     chainContext,
2024                     ref cpp,
2025                     ref status);
2026
2027             GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2028 #if TRAVE
2029             GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2030 #endif
2031             GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2032             return status.dwError;
2033         }
2034
2035         private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2036             switch ((CertificateProblem) errorCode) {
2037
2038                 case CertificateProblem.CertINVALIDNAME :
2039                 case CertificateProblem.CertCN_NO_MATCH :
2040                     return IgnoreCertProblem.invalid_name;
2041
2042                 case CertificateProblem.CertINVALIDPOLICY :
2043                 case CertificateProblem.CertPURPOSE :
2044                     return IgnoreCertProblem.invalid_policy;
2045
2046                 case CertificateProblem.CertEXPIRED :
2047                     return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2048
2049                 case CertificateProblem.CertVALIDITYPERIODNESTING :
2050                     return IgnoreCertProblem.not_time_nested;
2051
2052                 case CertificateProblem.CertCHAINING :
2053                 case CertificateProblem.CertUNTRUSTEDCA :
2054                 case CertificateProblem.CertUNTRUSTEDROOT :
2055                     return IgnoreCertProblem.allow_unknown_ca;
2056
2057                 case CertificateProblem.CertREVOKED :
2058                 case CertificateProblem.CertREVOCATION_FAILURE :
2059                 case CertificateProblem.CryptNOREVOCATIONCHECK:
2060                 case CertificateProblem.CryptREVOCATIONOFFLINE:
2061                     return IgnoreCertProblem.all_rev_unknown;
2062
2063                 case CertificateProblem.CertROLE:
2064                 case CertificateProblem.TrustBASICCONSTRAINTS:
2065                     return IgnoreCertProblem.invalid_basic_constraints;
2066
2067                 case CertificateProblem.CertWRONG_USAGE :
2068                     return IgnoreCertProblem.wrong_usage;
2069
2070                 default:
2071                     return 0;
2072             }
2073         }
2074
2075
2076         private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2077         {
2078             fatalError = false;
2079             SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2080             ArrayList certificateProblems = new ArrayList();
2081             unsafe {
2082                 uint status = 0;
2083                 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2084                 cppStruct.cbSize  = ChainPolicyParameter.StructSize;
2085                 cppStruct.dwFlags = 0;
2086
2087                 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2088                 cppStruct.pvExtraPolicyPara = &eppStruct;
2089
2090                 fixed (char* namePtr = hostName) {
2091                     if (ServicePointManager.CheckCertificateName){
2092                         eppStruct.pwszServerName = namePtr;
2093                     }
2094
2095                     while (true) {
2096                         status = VerifyChainPolicy(chainContext, ref cppStruct);
2097                         uint ignoreErrorMask = (uint)MapErrorCode(status);
2098
2099                         certificateProblems.Add(status);
2100
2101                         if (status == 0) {  // No more problems with the certificate?
2102                             break;          // Then break out of the callback loop
2103                         }
2104
2105                         if (ignoreErrorMask == 0) {  // Unrecognized error encountered
2106                             fatalError = true;
2107                             break;
2108                         }
2109                         else {
2110                             cppStruct.dwFlags |= ignoreErrorMask;
2111                             if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2112                                 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2113                             }
2114                         }
2115                     }
2116                 }
2117             }
2118
2119             return (uint[]) certificateProblems.ToArray(typeof(uint));
2120         }
2121
2122         internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2123         {
2124             if (sslPolicyErrors == 0)
2125                 return Accept(certificate, 0);
2126
2127             if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2128                 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2129             else {
2130                 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2131                     (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2132                 {
2133                     bool fatalError = false;
2134                     uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2135
2136                     if (fatalError) {
2137                         // By today design we cannot allow decider to ignore a fatal error.
2138                         // This error is fatal.
2139                         Accept(certificate, (int) SecurityStatus.InternalError);
2140                         return false;
2141                     }
2142
2143
2144                     if (certificateProblems.Length == 0)
2145                         return Accept(certificate, (int) CertificateProblem.OK);
2146
2147                     // Run each error through Accept().
2148                     foreach (uint error in certificateProblems)
2149                         if (!Accept(certificate, (int) error))
2150                             return false;
2151                 }
2152                 return true;
2153             }
2154         }
2155
2156 /* CONSIDER: Use this code when we switch to managed X509 API
2157         internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2158         {
2159             switch (status)
2160             {
2161             case X509ChainStatusFlags.NoError:       return CertificateProblem.OK;
2162             case X509ChainStatusFlags.NotTimeValid:  return CertificateProblem.CertEXPIRED;
2163             case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING;
2164             case X509ChainStatusFlags.Revoked:       return CertificateProblem.CertREVOKED;
2165             case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
2166             case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2167             case X509ChainStatusFlags.UntrustedRoot:    return CertificateProblem.CertUNTRUSTEDROOT;
2168             case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
2169             case X509ChainStatusFlags.Cyclic:           return CertificateProblem.CertCHAINING;             //??
2170             case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL;             //??
2171             case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
2172             case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS;
2173             case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME;
2174             case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2175             case X509ChainStatusFlags.HasNotDefinedNameConstraint:   return CertificateProblem.CertINVALIDNAME; //??
2176             case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2177             case X509ChainStatusFlags.HasExcludedNameConstraint:     return CertificateProblem.CertINVALIDNAME; //??
2178             case X509ChainStatusFlags.PartialChain:         return CertificateProblem.CertCHAINING;             //??
2179             case X509ChainStatusFlags.CtlNotTimeValid:      return CertificateProblem.CertEXPIRED;
2180             case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
2181             case X509ChainStatusFlags.CtlNotValidForUsage:  return CertificateProblem.CertWRONG_USAGE;
2182             case X509ChainStatusFlags.OfflineRevocation:    return CertificateProblem.CryptREVOCATIONOFFLINE;
2183             case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
2184             default: return (int) CertificateProblem.TrustSYSTEMERROR;  // unknown
2185             }
2186         }
2187 ***/
2188     }
2189     // Class implementing default certificate policy
2190     internal class DefaultCertPolicy : ICertificatePolicy {
2191         public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) {
2192             return problem == (int)CertificateProblem.OK;
2193         }
2194     }
2195 #endif // !FEATURE_PAL
2196
2197     internal enum TriState {
2198         Unspecified = -1,
2199         False = 0,
2200         True = 1
2201     }
2202
2203     internal enum DefaultPorts {
2204         DEFAULT_FTP_PORT = 21,
2205         DEFAULT_GOPHER_PORT = 70,
2206         DEFAULT_HTTP_PORT = 80,
2207         DEFAULT_HTTPS_PORT = 443,
2208         DEFAULT_NNTP_PORT = 119,
2209         DEFAULT_SMTP_PORT = 25,
2210         DEFAULT_TELNET_PORT = 23
2211     }
2212
2213     [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
2214     internal struct hostent {
2215         public IntPtr   h_name;
2216         public IntPtr   h_aliases;
2217         public short    h_addrtype;
2218         public short    h_length;
2219         public IntPtr   h_addr_list;
2220     }
2221
2222
2223     [StructLayout(LayoutKind.Sequential)]
2224     internal struct Blob {
2225         public int cbSize;
2226         public int pBlobData;
2227     }
2228
2229
2230     // This is only for internal code path i.e. TLS stream.
2231     // See comments on GetNextBuffer() method below.
2232     //
2233     internal class SplitWritesState
2234     {
2235         private const int c_SplitEncryptedBuffersSize = 64*1024;
2236         private BufferOffsetSize[] _UserBuffers;
2237         private int _Index;
2238         private int _LastBufferConsumed;
2239         private BufferOffsetSize[] _RealBuffers;
2240
2241         //
2242         internal SplitWritesState(BufferOffsetSize[] buffers)
2243         {
2244             _UserBuffers    = buffers;
2245             _LastBufferConsumed = 0;
2246             _Index          = 0;
2247             _RealBuffers = null;
2248         }
2249         //
2250         // Everything was handled
2251         //
2252         internal bool IsDone {
2253             get {
2254                 if (_LastBufferConsumed != 0)
2255                     return false;
2256
2257                 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2258                     if (_UserBuffers[index].Size != 0)
2259                         return false;
2260
2261                 return true;
2262             }
2263         }
2264         // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
2265         // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
2266         // up to c_SplitEncryptedBuffersSize total.
2267         // Note that upon return from here EncryptBuffers() may additonally split the input
2268         // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
2269         //
2270         //  Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2271         //
2272         //  Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2273         //
2274         internal BufferOffsetSize[] GetNextBuffers()
2275         {
2276             int curIndex = _Index;
2277             int currentTotalSize = 0;
2278             int lastChunkSize = 0;
2279
2280             int  firstBufferConsumed = _LastBufferConsumed;
2281
2282             for ( ;_Index < _UserBuffers.Length; ++_Index)
2283             {
2284                 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2285
2286                 currentTotalSize += lastChunkSize;
2287
2288                 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2289                 {
2290                     lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2291                     currentTotalSize = c_SplitEncryptedBuffersSize;
2292                     break;
2293                 }
2294
2295                 lastChunkSize = 0;
2296                 _LastBufferConsumed = 0;
2297             }
2298
2299             // Are we done done?
2300             if (currentTotalSize == 0)
2301                 return null;
2302
2303              // Do all buffers fit the limit?
2304             if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2305                 return _UserBuffers;
2306
2307             // We do have something to split and send out
2308             int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2309
2310             if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2311                 _RealBuffers = new BufferOffsetSize[buffersCount];
2312
2313             int j = 0;
2314             for (; curIndex < _Index; ++curIndex)
2315             {
2316                 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2317                 firstBufferConsumed = 0;
2318             }
2319
2320             if (lastChunkSize != 0)
2321             {
2322                 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2323                 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2324                 {
2325                     ++_Index;
2326                     _LastBufferConsumed = 0;
2327                 }
2328             }
2329
2330             return _RealBuffers;
2331
2332         }
2333     }
2334 }