Incorrect warning message on thread pool startup in full AOT:ed Windows build.
[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 #if MONO_FEATURE_WEB_STACK
985         internal static WebException IsolatedException {
986             get {
987                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure),WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null);
988             }
989         }
990
991         internal static WebException RequestAbortedException {
992             get {
993                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
994             }
995         }
996
997         internal static WebException CacheEntryNotFoundException {
998             get {
999                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound);
1000             }
1001         }
1002
1003         internal static WebException RequestProhibitedByCachePolicyException {
1004             get {
1005                 return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy);
1006             }
1007         }
1008 #endif
1009     }
1010
1011     internal enum WindowsInstallationType
1012     { 
1013         Unknown = 0,
1014         Client,
1015         Server,
1016         ServerCore,
1017         Embedded
1018     }
1019
1020     internal enum SecurityStatus
1021     {
1022         // Success / Informational
1023         OK                          =   0x00000000,
1024         ContinueNeeded              =   unchecked((int)0x00090312),
1025         CompleteNeeded              =   unchecked((int)0x00090313),
1026         CompAndContinue             =   unchecked((int)0x00090314),
1027         ContextExpired              =   unchecked((int)0x00090317),
1028         CredentialsNeeded           =   unchecked((int)0x00090320),
1029         Renegotiate                 =   unchecked((int)0x00090321),
1030         
1031         // Errors
1032         OutOfMemory                 =   unchecked((int)0x80090300),
1033         InvalidHandle               =   unchecked((int)0x80090301),
1034         Unsupported                 =   unchecked((int)0x80090302),
1035         TargetUnknown               =   unchecked((int)0x80090303),
1036         InternalError               =   unchecked((int)0x80090304),
1037         PackageNotFound             =   unchecked((int)0x80090305),
1038         NotOwner                    =   unchecked((int)0x80090306),
1039         CannotInstall               =   unchecked((int)0x80090307),
1040         InvalidToken                =   unchecked((int)0x80090308),
1041         CannotPack                  =   unchecked((int)0x80090309),
1042         QopNotSupported             =   unchecked((int)0x8009030A),
1043         NoImpersonation             =   unchecked((int)0x8009030B),
1044         LogonDenied                 =   unchecked((int)0x8009030C),
1045         UnknownCredentials          =   unchecked((int)0x8009030D),
1046         NoCredentials               =   unchecked((int)0x8009030E),
1047         MessageAltered              =   unchecked((int)0x8009030F),
1048         OutOfSequence               =   unchecked((int)0x80090310),
1049         NoAuthenticatingAuthority   =   unchecked((int)0x80090311),
1050         IncompleteMessage           =   unchecked((int)0x80090318),
1051         IncompleteCredentials       =   unchecked((int)0x80090320),
1052         BufferNotEnough             =   unchecked((int)0x80090321),
1053         WrongPrincipal              =   unchecked((int)0x80090322),
1054         TimeSkew                    =   unchecked((int)0x80090324),
1055         UntrustedRoot               =   unchecked((int)0x80090325),
1056         IllegalMessage              =   unchecked((int)0x80090326),
1057         CertUnknown                 =   unchecked((int)0x80090327),
1058         CertExpired                 =   unchecked((int)0x80090328),
1059         AlgorithmMismatch           =   unchecked((int)0x80090331),
1060         SecurityQosFailed           =   unchecked((int)0x80090332),
1061         SmartcardLogonRequired      =   unchecked((int)0x8009033E),
1062         UnsupportedPreauth          =   unchecked((int)0x80090343),
1063         BadBinding                  =   unchecked((int)0x80090346)
1064     }
1065
1066     internal enum ContentTypeValues {
1067         ChangeCipherSpec    = 0x14,
1068         Alert               = 0x15,
1069         HandShake           = 0x16,
1070         AppData             = 0x17,
1071         Unrecognized        = 0xFF,
1072     }
1073
1074     internal enum ContextAttribute {
1075         //
1076         // look into <sspi.h> and <schannel.h>
1077         //
1078         Sizes               = 0x00,
1079         Names               = 0x01,
1080         Lifespan            = 0x02,
1081         DceInfo             = 0x03,
1082         StreamSizes         = 0x04,
1083         //KeyInfo             = 0x05, must not be used, see ConnectionInfo instead
1084         Authority           = 0x06,
1085         // SECPKG_ATTR_PROTO_INFO          = 7,
1086         // SECPKG_ATTR_PASSWORD_EXPIRY     = 8,
1087         // SECPKG_ATTR_SESSION_KEY         = 9,
1088         PackageInfo         = 0x0A,
1089         // SECPKG_ATTR_USER_FLAGS          = 11,
1090         NegotiationInfo    = 0x0C,
1091         // SECPKG_ATTR_NATIVE_NAMES        = 13,
1092         // SECPKG_ATTR_FLAGS               = 14,
1093         // SECPKG_ATTR_USE_VALIDATED       = 15,
1094         // SECPKG_ATTR_CREDENTIAL_NAME     = 16,
1095         // SECPKG_ATTR_TARGET_INFORMATION  = 17,
1096         // SECPKG_ATTR_ACCESS_TOKEN        = 18,
1097         // SECPKG_ATTR_TARGET              = 19,
1098         // SECPKG_ATTR_AUTHENTICATION_ID   = 20,
1099         UniqueBindings      = 0x19,
1100         EndpointBindings    = 0x1A,
1101         ClientSpecifiedSpn  = 0x1B, // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27
1102         RemoteCertificate   = 0x53,
1103         LocalCertificate    = 0x54,
1104         RootStore           = 0x55,
1105         IssuerListInfoEx    = 0x59,
1106         ConnectionInfo      = 0x5A,
1107         // SECPKG_ATTR_EAP_KEY_BLOCK        0x5b   // returns SecPkgContext_EapKeyBlock  
1108         // SECPKG_ATTR_MAPPED_CRED_ATTR     0x5c   // returns SecPkgContext_MappedCredAttr  
1109         // SECPKG_ATTR_SESSION_INFO         0x5d   // returns SecPkgContext_SessionInfo  
1110         // SECPKG_ATTR_APP_DATA             0x5e   // sets/returns SecPkgContext_SessionAppData  
1111         // SECPKG_ATTR_REMOTE_CERTIFICATES  0x5F   // returns SecPkgContext_Certificates  
1112         // SECPKG_ATTR_CLIENT_CERT_POLICY   0x60   // sets    SecPkgCred_ClientCertCtlPolicy  
1113         // SECPKG_ATTR_CC_POLICY_RESULT     0x61   // returns SecPkgContext_ClientCertPolicyResult  
1114         // SECPKG_ATTR_USE_NCRYPT           0x62   // Sets the CRED_FLAG_USE_NCRYPT_PROVIDER FLAG on cred group  
1115         // SECPKG_ATTR_LOCAL_CERT_INFO      0x63   // returns SecPkgContext_CertInfo  
1116         // SECPKG_ATTR_CIPHER_INFO          0x64   // returns new CNG SecPkgContext_CipherInfo  
1117         // SECPKG_ATTR_EAP_PRF_INFO         0x65   // sets    SecPkgContext_EapPrfInfo  
1118         // SECPKG_ATTR_SUPPORTED_SIGNATURES 0x66   // returns SecPkgContext_SupportedSignatures  
1119         // SECPKG_ATTR_REMOTE_CERT_CHAIN    0x67   // returns PCCERT_CONTEXT  
1120         UiInfo              = 0x68, // sets SEcPkgContext_UiInfo  
1121     }
1122
1123     internal enum Endianness {
1124         Network             = 0x00,
1125         Native              = 0x10,
1126     }
1127
1128     internal enum CredentialUse {
1129         Inbound             = 0x1,
1130         Outbound            = 0x2,
1131         Both                = 0x3,
1132     }
1133
1134     internal enum BufferType {
1135         Empty               = 0x00,
1136         Data                = 0x01,
1137         Token               = 0x02,
1138         Parameters          = 0x03,
1139         Missing             = 0x04,
1140         Extra               = 0x05,
1141         Trailer             = 0x06,
1142         Header              = 0x07,
1143         Padding             = 0x09,    // non-data padding
1144         Stream              = 0x0A,
1145         ChannelBindings     = 0x0E,
1146         TargetHost          = 0x10,
1147         ReadOnlyFlag        = unchecked((int)0x80000000),
1148         ReadOnlyWithChecksum= 0x10000000
1149     }
1150
1151     internal enum ChainPolicyType {
1152         Base                = 1,
1153         Authenticode        = 2,
1154         Authenticode_TS     = 3,
1155         SSL                 = 4,
1156         BasicConstraints    = 5,
1157         NtAuth              = 6,
1158     }
1159
1160     internal enum IgnoreCertProblem {
1161         not_time_valid              = 0x00000001,
1162         ctl_not_time_valid          = 0x00000002,
1163         not_time_nested             = 0x00000004,
1164         invalid_basic_constraints   = 0x00000008,
1165
1166         all_not_time_valid          =
1167             not_time_valid          |
1168             ctl_not_time_valid      |
1169             not_time_nested,
1170
1171         allow_unknown_ca            = 0x00000010,
1172         wrong_usage                 = 0x00000020,
1173         invalid_name                = 0x00000040,
1174         invalid_policy              = 0x00000080,
1175         end_rev_unknown             = 0x00000100,
1176         ctl_signer_rev_unknown      = 0x00000200,
1177         ca_rev_unknown              = 0x00000400,
1178         root_rev_unknown            = 0x00000800,
1179
1180         all_rev_unknown             =
1181             end_rev_unknown         |
1182             ctl_signer_rev_unknown  |
1183             ca_rev_unknown          |
1184             root_rev_unknown,
1185         none =
1186             not_time_valid |
1187             ctl_not_time_valid |
1188             not_time_nested |
1189             invalid_basic_constraints |
1190             allow_unknown_ca |
1191             wrong_usage |
1192             invalid_name |
1193             invalid_policy |
1194             end_rev_unknown |
1195             ctl_signer_rev_unknown |
1196             ca_rev_unknown |
1197             root_rev_unknown
1198     }
1199
1200     internal enum CertUsage {
1201         MatchTypeAnd    = 0x00,
1202         MatchTypeOr     = 0x01,
1203     }
1204
1205 #if !FEATURE_PAL
1206
1207     [StructLayout(LayoutKind.Sequential)]
1208     internal unsafe struct ChainPolicyParameter {
1209         public uint cbSize;
1210         public uint dwFlags;
1211         public SSL_EXTRA_CERT_CHAIN_POLICY_PARA* pvExtraPolicyPara;
1212
1213         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyParameter));
1214     }
1215
1216     [StructLayout(LayoutKind.Sequential)]
1217     internal unsafe struct SSL_EXTRA_CERT_CHAIN_POLICY_PARA {
1218
1219         [StructLayout(LayoutKind.Explicit)]
1220         internal struct U {
1221               [FieldOffset(0)] internal uint cbStruct;  //DWORD
1222               [FieldOffset(0)] internal uint cbSize;    //DWORD
1223         };
1224         internal U u;
1225         internal int    dwAuthType;  //DWORD
1226         internal uint   fdwChecks;   //DWORD
1227         internal char*  pwszServerName; //WCHAR* // used to check against CN=xxxx
1228
1229         internal SSL_EXTRA_CERT_CHAIN_POLICY_PARA(bool amIServer)
1230         {
1231             u.cbStruct = StructSize;
1232             u.cbSize   = StructSize;
1233             //#      define      AUTHTYPE_CLIENT         1
1234             //#      define      AUTHTYPE_SERVER         2
1235             dwAuthType = amIServer? 1: 2;
1236             fdwChecks = 0;
1237             pwszServerName = null;
1238         }
1239         static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
1240     }
1241
1242     [StructLayout(LayoutKind.Sequential)]
1243     internal unsafe struct ChainPolicyStatus {
1244         public uint   cbSize;
1245         public uint   dwError;
1246         public uint   lChainIndex;
1247         public uint   lElementIndex;
1248         public void*  pvExtraPolicyStatus;
1249
1250         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainPolicyStatus));
1251     }
1252
1253     [StructLayout(LayoutKind.Sequential)]
1254     internal unsafe struct CertEnhKeyUse {
1255
1256         public uint   cUsageIdentifier;
1257         public void*  rgpszUsageIdentifier;
1258
1259 #if TRAVE
1260         public override string ToString() {
1261             return "cUsageIdentifier="+cUsageIdentifier.ToString()+ " rgpszUsageIdentifier=" + new IntPtr(rgpszUsageIdentifier).ToString("x");
1262         }
1263 #endif
1264     };
1265
1266     [StructLayout(LayoutKind.Sequential)]
1267     internal struct CertUsageMatch {
1268         public CertUsage     dwType;
1269         public CertEnhKeyUse Usage;
1270 #if TRAVE
1271         public override string ToString() {
1272             return "dwType="+dwType.ToString()+" "+Usage.ToString();
1273         }
1274 #endif
1275     };
1276
1277     [StructLayout(LayoutKind.Sequential)]
1278     internal struct ChainParameters {
1279         public uint cbSize;
1280         public CertUsageMatch RequestedUsage;
1281         public CertUsageMatch RequestedIssuancePolicy;
1282         public uint           UrlRetrievalTimeout;
1283         public int            BoolCheckRevocationFreshnessTime;
1284         public uint           RevocationFreshnessTime;
1285
1286
1287         public static readonly uint StructSize = (uint) Marshal.SizeOf(typeof(ChainParameters));
1288 #if TRAVE
1289         public override string ToString() {
1290             return "cbSize="+cbSize.ToString()+" "+RequestedUsage.ToString();
1291         }
1292 #endif
1293     };
1294
1295     [StructLayout(LayoutKind.Sequential)]
1296     struct _CERT_CHAIN_ELEMENT
1297     {
1298         public uint cbSize;
1299         public IntPtr pCertContext;
1300         // Since this structure is allocated by unmanaged code, we can
1301         // omit the fileds below since we don't need to access them
1302         // CERT_TRUST_STATUS   TrustStatus;
1303         // IntPtr                pRevocationInfo;
1304         // IntPtr                pIssuanceUsage;
1305         // IntPtr                pApplicationUsage;
1306     }
1307
1308     // CRYPTOAPI_BLOB
1309     //[StructLayout(LayoutKind.Sequential)]
1310     //unsafe struct CryptoBlob {
1311     //    // public uint cbData;
1312     //    // public byte* pbData;
1313     //    public uint dataSize;
1314     //    public byte* dataBlob;
1315     //}
1316
1317     // SecPkgContext_IssuerListInfoEx
1318     [StructLayout(LayoutKind.Sequential)]
1319     unsafe struct IssuerListInfoEx {
1320         public SafeHandle aIssuers;
1321         public uint cIssuers;
1322
1323         public unsafe IssuerListInfoEx(SafeHandle handle, byte[] nativeBuffer) {
1324             aIssuers = handle;
1325             fixed(byte* voidPtr = nativeBuffer) {
1326                 // if this breaks on 64 bit, do the sizeof(IntPtr) trick
1327                 cIssuers = *((uint*)(voidPtr + IntPtr.Size));
1328             }
1329         }
1330     }
1331
1332
1333     [StructLayout(LayoutKind.Sequential)]
1334     internal struct SecureCredential {
1335
1336 /*
1337 typedef struct _SCHANNEL_CRED
1338 {
1339     DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION
1340     DWORD           cCreds;
1341     PCCERT_CONTEXT *paCred;
1342     HCERTSTORE      hRootStore;
1343
1344     DWORD           cMappers;
1345     struct _HMAPPER **aphMappers;
1346
1347     DWORD           cSupportedAlgs;
1348     ALG_ID *        palgSupportedAlgs;
1349
1350     DWORD           grbitEnabledProtocols;
1351     DWORD           dwMinimumCipherStrength;
1352     DWORD           dwMaximumCipherStrength;
1353     DWORD           dwSessionLifespan;
1354     DWORD           dwFlags;
1355     DWORD           reserved;
1356 } SCHANNEL_CRED, *PSCHANNEL_CRED;
1357 */
1358
1359         public const int CurrentVersion = 0x4;
1360
1361         public int version;
1362         public int cCreds;
1363
1364         // ptr to an array of pointers
1365         // There is a hack done with this field.  AcquireCredentialsHandle requires an array of
1366         // certificate handles; we only ever use one.  In order to avoid pinning a one element array,
1367         // we copy this value onto the stack, create a pointer on the stack to the copied value,
1368         // and replace this field with the pointer, during the call to AcquireCredentialsHandle.
1369         // Then we fix it up afterwards.  Fine as long as all the SSPI credentials are not
1370         // supposed to be threadsafe.
1371         public IntPtr certContextArray;
1372
1373         private readonly IntPtr rootStore;               // == always null, OTHERWISE NOT RELIABLE
1374         public int cMappers;
1375         private readonly IntPtr phMappers;               // == always null, OTHERWISE NOT RELIABLE
1376         public int cSupportedAlgs;
1377         private readonly IntPtr palgSupportedAlgs;       // == always null, OTHERWISE NOT RELIABLE
1378         public SchProtocols grbitEnabledProtocols;
1379         public int dwMinimumCipherStrength;
1380         public int dwMaximumCipherStrength;
1381         public int dwSessionLifespan;
1382         public SecureCredential.Flags dwFlags;
1383         public int reserved;
1384
1385         [Flags]
1386         public enum Flags {
1387             Zero            = 0,
1388             NoSystemMapper  = 0x02,
1389             NoNameCheck     = 0x04,
1390             ValidateManual  = 0x08,
1391             NoDefaultCred   = 0x10,
1392             ValidateAuto    = 0x20,
1393             UseStrongCrypto = 0x00400000,
1394         }
1395
1396         public SecureCredential(int version, X509Certificate certificate, SecureCredential.Flags flags, SchProtocols protocols, EncryptionPolicy policy) {
1397             // default values required for a struct
1398             rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
1399             cCreds = cMappers = cSupportedAlgs = 0;
1400
1401             if (policy == EncryptionPolicy.RequireEncryption) {
1402                 // Prohibit null encryption cipher
1403                 dwMinimumCipherStrength = 0;
1404                 dwMaximumCipherStrength = 0;
1405             }
1406             else if (policy == EncryptionPolicy.AllowNoEncryption) {
1407                 // Allow null encryption cipher in addition to other ciphers
1408                 dwMinimumCipherStrength = -1;
1409                 dwMaximumCipherStrength =  0;
1410             }
1411             else if (policy == EncryptionPolicy.NoEncryption) {
1412                 // Suppress all encryption and require null encryption cipher only
1413                 dwMinimumCipherStrength = -1;
1414                 dwMaximumCipherStrength = -1;
1415             }
1416             else {
1417                 throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "EncryptionPolicy"), "policy");
1418             }
1419             
1420             dwSessionLifespan = reserved = 0;
1421             this.version = version;
1422             dwFlags = flags;
1423             grbitEnabledProtocols = protocols;
1424             if (certificate != null) {
1425                 certContextArray = certificate.Handle;
1426                 cCreds = 1;
1427             }
1428         }
1429
1430         [System.Diagnostics.Conditional("TRAVE")]
1431         internal void DebugDump() {
1432             GlobalLog.Print("SecureCredential #"+GetHashCode());
1433             GlobalLog.Print("    version                 = " + version);
1434             GlobalLog.Print("    cCreds                  = " + cCreds);
1435             GlobalLog.Print("    certContextArray        = " + String.Format("0x{0:x}", certContextArray));
1436             GlobalLog.Print("    rootStore               = " + String.Format("0x{0:x}", rootStore));
1437             GlobalLog.Print("    cMappers                = " + cMappers);
1438             GlobalLog.Print("    phMappers               = " + String.Format("0x{0:x}", phMappers));
1439             GlobalLog.Print("    cSupportedAlgs          = " + cSupportedAlgs);
1440             GlobalLog.Print("    palgSupportedAlgs       = " + String.Format("0x{0:x}", palgSupportedAlgs));
1441             GlobalLog.Print("    grbitEnabledProtocols   = " + String.Format("0x{0:x}", grbitEnabledProtocols));
1442             GlobalLog.Print("    dwMinimumCipherStrength = " + dwMinimumCipherStrength);
1443             GlobalLog.Print("    dwMaximumCipherStrength = " + dwMaximumCipherStrength);
1444             GlobalLog.Print("    dwSessionLifespan       = " + String.Format("0x{0:x}", dwSessionLifespan));
1445             GlobalLog.Print("    dwFlags                 = " + String.Format("0x{0:x}", dwFlags));
1446             GlobalLog.Print("    reserved                = " + String.Format("0x{0:x}", reserved));
1447         }
1448
1449     } // SecureCredential
1450
1451 #endif // !FEATURE_PAL
1452
1453     [StructLayout(LayoutKind.Sequential)]
1454     internal unsafe struct SecurityBufferStruct {
1455         public int          count;
1456         public BufferType   type;
1457         public IntPtr       token;
1458
1459         public static readonly int Size = sizeof(SecurityBufferStruct);
1460     }
1461
1462     internal class SecurityBuffer {
1463         public int size;
1464         public BufferType type;
1465         public byte[] token;
1466         public SafeHandle unmanagedToken;
1467         public int offset;
1468
1469         public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) {
1470             GlobalLog.Assert(offset >= 0 && offset <= (data == null ? 0 : data.Length), "SecurityBuffer::.ctor", "'offset' out of range.  [" + offset + "]");
1471             GlobalLog.Assert(size >= 0 && size <= (data == null ? 0 : data.Length - offset), "SecurityBuffer::.ctor", "'size' out of range.  [" + size + "]");
1472                         
1473             this.offset = data == null || offset < 0 ? 0 : Math.Min(offset, data.Length);
1474             this.size   = data == null || size < 0 ? 0 : Math.Min(size, data.Length - this.offset);
1475             this.type   = tokentype;
1476             this.token  = size == 0 ? null : data;
1477         }
1478
1479         public SecurityBuffer(byte[] data, BufferType tokentype) {
1480             this.size   = data == null ? 0 : data.Length;
1481             this.type   = tokentype;
1482             this.token  = size == 0 ? null : data;
1483         }
1484
1485         public SecurityBuffer(int size, BufferType tokentype) {
1486             GlobalLog.Assert(size >= 0, "SecurityBuffer::.ctor", "'size' out of range.  [" + size.ToString(NumberFormatInfo.InvariantInfo) + "]");
1487
1488             this.size   = size;
1489             this.type   = tokentype;
1490             this.token  = size == 0 ? null : new byte[size];
1491         }
1492
1493         public SecurityBuffer(ChannelBinding binding) {
1494             this.size           = (binding == null ? 0 : binding.Size);
1495             this.type           = BufferType.ChannelBindings;
1496             this.unmanagedToken = binding;
1497         }
1498     }
1499
1500     [StructLayout(LayoutKind.Sequential)]
1501     internal unsafe class SecurityBufferDescriptor {
1502     /*
1503     typedef struct _SecBufferDesc {
1504         ULONG        ulVersion;
1505         ULONG        cBuffers;
1506         PSecBuffer   pBuffers;
1507     } SecBufferDesc, * PSecBufferDesc;
1508     */
1509             public  readonly    int     Version;
1510             public  readonly    int     Count;
1511             public  void*       UnmanagedPointer;
1512
1513         public SecurityBufferDescriptor(int count) {
1514             Version = 0;
1515             Count = count;
1516             UnmanagedPointer = null;
1517         }
1518
1519         [System.Diagnostics.Conditional("TRAVE")]
1520         internal void DebugDump() {
1521             GlobalLog.Print("SecurityBufferDescriptor #" + ValidationHelper.HashString(this));
1522             GlobalLog.Print("    version             = " + Version);
1523             GlobalLog.Print("    count               = " + Count);
1524             GlobalLog.Print("    securityBufferArray = 0x" + (new IntPtr(UnmanagedPointer)).ToString("x"));
1525         }
1526     } // SecurityBufferDescriptor
1527
1528     internal  enum    CertificateEncoding {
1529         Zero                     = 0,
1530         X509AsnEncoding          = unchecked((int)0x00000001),
1531         X509NdrEncoding          = unchecked((int)0x00000002),
1532         Pkcs7AsnEncoding         = unchecked((int)0x00010000),
1533         Pkcs7NdrEncoding         = unchecked((int)0x00020000),
1534         AnyAsnEncoding           = X509AsnEncoding|Pkcs7AsnEncoding
1535     }
1536
1537     internal  enum    CertificateProblem {
1538         OK                          =   0x00000000,
1539         TrustNOSIGNATURE            = unchecked((int)0x800B0100),
1540         CertEXPIRED                 = unchecked((int)0x800B0101),
1541         CertVALIDITYPERIODNESTING   = unchecked((int)0x800B0102),
1542         CertROLE                    = unchecked((int)0x800B0103),
1543         CertPATHLENCONST            = unchecked((int)0x800B0104),
1544         CertCRITICAL                = unchecked((int)0x800B0105),
1545         CertPURPOSE                 = unchecked((int)0x800B0106),
1546         CertISSUERCHAINING          = unchecked((int)0x800B0107),
1547         CertMALFORMED               = unchecked((int)0x800B0108),
1548         CertUNTRUSTEDROOT           = unchecked((int)0x800B0109),
1549         CertCHAINING                = unchecked((int)0x800B010A),
1550         CertREVOKED                 = unchecked((int)0x800B010C),
1551         CertUNTRUSTEDTESTROOT       = unchecked((int)0x800B010D),
1552         CertREVOCATION_FAILURE      = unchecked((int)0x800B010E),
1553         CertCN_NO_MATCH             = unchecked((int)0x800B010F),
1554         CertWRONG_USAGE             = unchecked((int)0x800B0110),
1555         TrustEXPLICITDISTRUST       = unchecked((int)0x800B0111),
1556         CertUNTRUSTEDCA             = unchecked((int)0x800B0112),
1557         CertINVALIDPOLICY           = unchecked((int)0x800B0113),
1558         CertINVALIDNAME             = unchecked((int)0x800B0114),
1559
1560         CryptNOREVOCATIONCHECK       = unchecked((int)0x80092012),
1561         CryptREVOCATIONOFFLINE       = unchecked((int)0x80092013),
1562
1563         TrustSYSTEMERROR            = unchecked((int)0x80096001),
1564         TrustNOSIGNERCERT           = unchecked((int)0x80096002),
1565         TrustCOUNTERSIGNER          = unchecked((int)0x80096003),
1566         TrustCERTSIGNATURE          = unchecked((int)0x80096004),
1567         TrustTIMESTAMP              = unchecked((int)0x80096005),
1568         TrustBADDIGEST              = unchecked((int)0x80096010),
1569         TrustBASICCONSTRAINTS       = unchecked((int)0x80096019),
1570         TrustFINANCIALCRITERIA      = unchecked((int)0x8009601E),
1571     }
1572
1573     [StructLayout(LayoutKind.Sequential)]
1574     internal class SecChannelBindings
1575     {
1576         internal int dwInitiatorAddrType;
1577         internal int cbInitiatorLength;
1578         internal int dwInitiatorOffset;
1579
1580         internal int dwAcceptorAddrType;
1581         internal int cbAcceptorLength;
1582         internal int dwAcceptorOffset;
1583
1584         internal int cbApplicationDataLength;
1585         internal int dwApplicationDataOffset;
1586     }
1587
1588     //
1589     // WebRequestPrefixElement
1590     //
1591     // This is an element of the prefix list. It contains the prefix and the
1592     // interface to be called to create a request for that prefix.
1593     //
1594
1595     /// <devdoc>
1596     ///    <para>[To be supplied.]</para>
1597     /// </devdoc>
1598     // internal class WebRequestPrefixElement {
1599     internal class WebRequestPrefixElement  {
1600
1601         /// <devdoc>
1602         ///    <para>[To be supplied.]</para>
1603         /// </devdoc>
1604         public    string              Prefix;
1605         /// <devdoc>
1606         ///    <para>[To be supplied.]</para>
1607         /// </devdoc>
1608         internal    IWebRequestCreate   creator;
1609         /// <devdoc>
1610         ///    <para>[To be supplied.]</para>
1611         /// </devdoc>
1612         internal    Type   creatorType;
1613
1614         public IWebRequestCreate Creator {
1615             get {
1616                 if (creator == null && creatorType != null) {
1617                     lock(this) {
1618                         if (creator == null) {
1619                             creator = (IWebRequestCreate)Activator.CreateInstance(
1620                                                         creatorType,
1621                                                         BindingFlags.CreateInstance
1622                                                         | BindingFlags.Instance
1623                                                         | BindingFlags.NonPublic
1624                                                         | BindingFlags.Public,
1625                                                         null,          // Binder
1626                                                         new object[0], // no arguments
1627                                                         CultureInfo.InvariantCulture
1628                                                         );
1629                         }
1630                     }
1631                 }
1632
1633                 return creator;
1634             }
1635
1636             set {
1637                 creator = value;
1638             }
1639         }
1640
1641         public WebRequestPrefixElement(string P, Type creatorType) {
1642             // verify that its of the proper type of IWebRequestCreate
1643             if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType))
1644             {
1645                 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast,
1646                                                                 creatorType.AssemblyQualifiedName,
1647                                                                 "IWebRequestCreate"));
1648             }
1649
1650             Prefix = P;
1651             this.creatorType = creatorType;
1652         }
1653
1654         /// <devdoc>
1655         ///    <para>[To be supplied.]</para>
1656         /// </devdoc>
1657         public WebRequestPrefixElement(string P, IWebRequestCreate C) {
1658             Prefix = P;
1659             Creator = C;
1660         }
1661
1662     } // class PrefixListElement
1663
1664
1665 #if MONO_FEATURE_WEB_STACK
1666
1667     //
1668     // HttpRequestCreator.
1669     //
1670     // This is the class that we use to create HTTP and HTTPS requests.
1671     //
1672
1673     internal class HttpRequestCreator : IWebRequestCreate {
1674
1675         /*++
1676
1677          Create - Create an HttpWebRequest.
1678
1679             This is our method to create an HttpWebRequest. We register
1680             for HTTP and HTTPS Uris, and this method is called when a request
1681             needs to be created for one of those.
1682
1683
1684             Input:
1685                     Uri             - Uri for request being created.
1686
1687             Returns:
1688                     The newly created HttpWebRequest.
1689
1690          --*/
1691
1692         public WebRequest Create( Uri Uri ) {
1693             //
1694             // Note, DNS permissions check will not happen on WebRequest
1695             //
1696             return new HttpWebRequest(Uri, null);
1697         }
1698
1699     } // class HttpRequestCreator
1700
1701     //
1702     // WebSocketHttpRequestCreator.
1703     //
1704     // This is the class that we use to create WebSocket connection requests.
1705     //
1706
1707     internal class WebSocketHttpRequestCreator : IWebRequestCreate
1708     {
1709         private string m_httpScheme;
1710
1711         // This ctor is used to create a WebSocketHttpRequestCreator.
1712         // We will do a URI change to update the scheme with Http or Https scheme. The usingHttps boolean is 
1713         // used to indicate whether the created HttpWebRequest should take the https scheme or not.
1714         public WebSocketHttpRequestCreator(bool usingHttps)
1715         {
1716             m_httpScheme = usingHttps ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
1717         }
1718
1719         /*++
1720
1721          Create - Create an HttpWebRequest.
1722
1723             This is our method to create an HttpWebRequest for WebSocket connection. We register
1724             We will register it for custom Uri prefixes. And this method is called when a request
1725             needs to be created for one of those. The created HttpWebRequest will still be with Http or Https
1726             scheme, depending on the m_httpScheme field of this object.
1727
1728
1729             Input:
1730                     Uri             - Uri for request being created.
1731
1732             Returns:
1733                     The newly created HttpWebRequest for WebSocket connection.
1734
1735          --*/
1736
1737         public WebRequest Create(Uri Uri)
1738         {
1739             UriBuilder uriBuilder = new UriBuilder(Uri);
1740             uriBuilder.Scheme = m_httpScheme;
1741             HttpWebRequest request = new HttpWebRequest(uriBuilder.Uri, null, true, "WebSocket" + Guid.NewGuid());
1742             WebSocketHelpers.PrepareWebRequest(ref request);
1743             return request;
1744         }
1745
1746     } // class WebSocketHttpRequestCreator
1747
1748
1749
1750
1751     //
1752     //  CoreResponseData - Used to store result of HTTP header parsing and
1753     //      response parsing.  Also Contains new stream to use, and
1754     //      is used as core of new Response
1755     //
1756     internal class CoreResponseData {
1757
1758         // Status Line Response Values
1759         public HttpStatusCode m_StatusCode;
1760         public string m_StatusDescription;
1761         public bool m_IsVersionHttp11;
1762
1763         // Content Length needed for semantics, -1 if chunked
1764         public long m_ContentLength;
1765
1766         // Response Headers
1767         public WebHeaderCollection m_ResponseHeaders;
1768
1769         // ConnectStream - for reading actual data
1770         public Stream m_ConnectStream;
1771
1772         internal CoreResponseData Clone() {
1773             CoreResponseData cloneResponseData = new CoreResponseData();
1774             cloneResponseData.m_StatusCode        = m_StatusCode;
1775             cloneResponseData.m_StatusDescription = m_StatusDescription;
1776             cloneResponseData.m_IsVersionHttp11   = m_IsVersionHttp11;
1777             cloneResponseData.m_ContentLength     = m_ContentLength;
1778             cloneResponseData.m_ResponseHeaders   = m_ResponseHeaders;
1779             cloneResponseData.m_ConnectStream     = m_ConnectStream;
1780             return cloneResponseData;
1781         }
1782
1783     }
1784 #endif
1785
1786
1787     internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
1788
1789     //
1790     // this class contains known header names
1791     //
1792
1793     internal static class HttpKnownHeaderNames {
1794
1795         public const string CacheControl = "Cache-Control";
1796         public const string Connection = "Connection";
1797         public const string Date = "Date";
1798         public const string KeepAlive = "Keep-Alive";
1799         public const string Pragma = "Pragma";
1800         public const string ProxyConnection = "Proxy-Connection";
1801         public const string Trailer = "Trailer";
1802         public const string TransferEncoding = "Transfer-Encoding";
1803         public const string Upgrade = "Upgrade";
1804         public const string Via = "Via";
1805         public const string Warning = "Warning";
1806         public const string ContentLength = "Content-Length";
1807         public const string ContentType = "Content-Type";
1808         public const string ContentDisposition = "Content-Disposition";
1809         public const string ContentEncoding = "Content-Encoding";
1810         public const string ContentLanguage = "Content-Language";
1811         public const string ContentLocation = "Content-Location";
1812         public const string ContentRange = "Content-Range";
1813         public const string Expires = "Expires";
1814         public const string LastModified = "Last-Modified";
1815         public const string Age = "Age";
1816         public const string Location = "Location";
1817         public const string ProxyAuthenticate = "Proxy-Authenticate";
1818         public const string RetryAfter = "Retry-After";
1819         public const string Server = "Server";
1820         public const string SetCookie = "Set-Cookie";
1821         public const string SetCookie2 = "Set-Cookie2";
1822         public const string Vary = "Vary";
1823         public const string WWWAuthenticate = "WWW-Authenticate";
1824         public const string Accept = "Accept";
1825         public const string AcceptCharset = "Accept-Charset";
1826         public const string AcceptEncoding = "Accept-Encoding";
1827         public const string AcceptLanguage = "Accept-Language";
1828         public const string Authorization = "Authorization";
1829         public const string Cookie = "Cookie";
1830         public const string Cookie2 = "Cookie2";
1831         public const string Expect = "Expect";
1832         public const string From = "From";
1833         public const string Host = "Host";
1834         public const string IfMatch = "If-Match";
1835         public const string IfModifiedSince = "If-Modified-Since";
1836         public const string IfNoneMatch = "If-None-Match";
1837         public const string IfRange = "If-Range";
1838         public const string IfUnmodifiedSince = "If-Unmodified-Since";
1839         public const string MaxForwards = "Max-Forwards";
1840         public const string ProxyAuthorization = "Proxy-Authorization";
1841         public const string Referer = "Referer";
1842         public const string Range = "Range";
1843         public const string UserAgent = "User-Agent";
1844         public const string ContentMD5 = "Content-MD5";
1845         public const string ETag = "ETag";
1846         public const string TE = "TE";
1847         public const string Allow = "Allow";
1848         public const string AcceptRanges = "Accept-Ranges";
1849         public const string P3P = "P3P";
1850         public const string XPoweredBy = "X-Powered-By";
1851         public const string XAspNetVersion = "X-AspNet-Version";
1852         public const string SecWebSocketKey = "Sec-WebSocket-Key";
1853         public const string SecWebSocketExtensions = "Sec-WebSocket-Extensions";
1854         public const string SecWebSocketAccept = "Sec-WebSocket-Accept";
1855         public const string Origin = "Origin";
1856         public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
1857         public const string SecWebSocketVersion = "Sec-WebSocket-Version"; 
1858     }
1859
1860     /// <devdoc>
1861     ///    <para>
1862     ///       Represents the method that will notify callers when a continue has been
1863     ///       received by the client.
1864     ///    </para>
1865     /// </devdoc>
1866     // Delegate type for us to notify callers when we receive a continue
1867     public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
1868
1869     //
1870     // HttpWriteMode - used to control the way in which an entity Body is posted.
1871     //
1872     enum HttpWriteMode {
1873         Unknown         = 0,
1874         ContentLength   = 1,
1875         Chunked         = 2,
1876         Buffer          = 3,
1877         None            = 4,
1878     }
1879
1880     // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
1881     delegate void UnlockConnectionDelegate();
1882
1883     enum HttpBehaviour : byte {
1884         Unknown                     = 0,
1885         HTTP10                      = 1,
1886         HTTP11PartiallyCompliant    = 2,
1887         HTTP11                      = 3,
1888     }
1889
1890     internal enum HttpProcessingResult {
1891         Continue  = 0,
1892         ReadWait  = 1,
1893         WriteWait = 2,
1894     }
1895
1896 #if MONO_FEATURE_WEB_STACK
1897     //
1898     // HttpVerb - used to define various per Verb Properties
1899     //
1900
1901     //
1902     // Note - this is a place holder for Verb properties,
1903     //  the following two bools can most likely be combined into
1904     //  a single Enum type.  And the Verb can be incorporated.
1905     //
1906     class KnownHttpVerb {
1907         internal string Name; // verb name
1908
1909         internal bool RequireContentBody; // require content body to be sent
1910         internal bool ContentBodyNotAllowed; // not allowed to send content body
1911         internal bool ConnectRequest; // special semantics for a connect request
1912         internal bool ExpectNoContentResponse; // response will not have content body
1913
1914         internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse) {
1915             Name = name;
1916             RequireContentBody = requireContentBody;
1917             ContentBodyNotAllowed = contentBodyNotAllowed;
1918             ConnectRequest = connectRequest;
1919             ExpectNoContentResponse = expectNoContentResponse;
1920         }
1921
1922         // Force an an init, before we use them
1923         private static ListDictionary NamedHeaders;
1924
1925         // known verbs
1926         internal static KnownHttpVerb Get;
1927         internal static KnownHttpVerb Connect;
1928         internal static KnownHttpVerb Head;
1929         internal static KnownHttpVerb Put;
1930         internal static KnownHttpVerb Post;
1931         internal static KnownHttpVerb MkCol;
1932
1933         //
1934         // InitializeKnownVerbs - Does basic init for this object,
1935         //  such as creating defaultings and filling them
1936         //
1937         static KnownHttpVerb() {
1938             NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
1939             Get = new KnownHttpVerb("GET", false, true, false, false);
1940             Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
1941             Head = new KnownHttpVerb("HEAD", false, true, false, true);
1942             Put = new KnownHttpVerb("PUT", true, false, false, false);
1943             Post = new KnownHttpVerb("POST", true, false, false, false);
1944             MkCol = new KnownHttpVerb("MKCOL",false,false,false,false);
1945             NamedHeaders[Get.Name] = Get;
1946             NamedHeaders[Connect.Name] = Connect;
1947             NamedHeaders[Head.Name] = Head;
1948             NamedHeaders[Put.Name] = Put;
1949             NamedHeaders[Post.Name] = Post;
1950             NamedHeaders[MkCol.Name] = MkCol;
1951         }
1952
1953         public bool Equals(KnownHttpVerb verb) {
1954             return this==verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase)==0;
1955         }
1956
1957         public static KnownHttpVerb Parse(string name) {
1958             KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
1959             if (knownHttpVerb==null) {
1960                 // unknown verb, default behaviour
1961                 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
1962             }
1963             return knownHttpVerb;
1964         }
1965     }
1966
1967
1968     //
1969     // HttpProtocolUtils - A collection of utility functions for HTTP usage.
1970     //
1971
1972     internal class HttpProtocolUtils {
1973
1974         private HttpProtocolUtils() {
1975         }
1976
1977         //
1978         // extra buffers for build/parsing, recv/send HTTP data,
1979         //  at some point we should consolidate
1980         //
1981
1982
1983         // parse String to DateTime format.
1984         internal static DateTime string2date(String S) {
1985             DateTime dtOut;
1986             if (HttpDateParse.ParseHttpDate(S,out dtOut)) {
1987                 return dtOut;
1988             }
1989             else {
1990                 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
1991             }
1992
1993         }
1994
1995         // convert Date to String using RFC 1123 pattern
1996         internal static string date2string(DateTime D) {
1997             DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
1998             return D.ToUniversalTime().ToString("R", dateFormat);
1999         }
2000     }
2001 #endif
2002
2003 #if !FEATURE_PAL
2004     // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider
2005     internal class  PolicyWrapper {
2006         private const uint          IgnoreUnmatchedCN       = 0x00001000;
2007         private ICertificatePolicy  fwdPolicy;
2008         private ServicePoint        srvPoint;
2009         private WebRequest          request;
2010
2011         internal PolicyWrapper(ICertificatePolicy policy, ServicePoint sp, WebRequest wr) {
2012             this.fwdPolicy = policy;
2013             srvPoint = sp;
2014             request = wr;
2015         }
2016
2017         public bool Accept(X509Certificate Certificate, int CertificateProblem) {
2018             return fwdPolicy.CheckValidationResult(srvPoint, Certificate, request, CertificateProblem);
2019         }
2020
2021         internal static uint VerifyChainPolicy(SafeFreeCertChain chainContext, ref ChainPolicyParameter cpp) {
2022             GlobalLog.Enter("PolicyWrapper::VerifyChainPolicy", "chainContext="+ chainContext + ", options="+String.Format("0x{0:x}", cpp.dwFlags));
2023             ChainPolicyStatus status = new ChainPolicyStatus();
2024             status.cbSize = ChainPolicyStatus.StructSize;
2025             int errorCode =
2026                 UnsafeNclNativeMethods.NativePKI.CertVerifyCertificateChainPolicy(
2027                     (IntPtr) ChainPolicyType.SSL,
2028                     chainContext,
2029                     ref cpp,
2030                     ref status);
2031
2032             GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() CertVerifyCertificateChainPolicy returned: " + errorCode);
2033 #if TRAVE
2034             GlobalLog.Print("PolicyWrapper::VerifyChainPolicy() error code: " + status.dwError+String.Format(" [0x{0:x8}", status.dwError) + " " + SecureChannel.MapSecurityStatus(status.dwError) + "]");
2035 #endif
2036             GlobalLog.Leave("PolicyWrapper::VerifyChainPolicy", status.dwError.ToString());
2037             return status.dwError;
2038         }
2039
2040         private static IgnoreCertProblem MapErrorCode(uint errorCode) {
2041             switch ((CertificateProblem) errorCode) {
2042
2043                 case CertificateProblem.CertINVALIDNAME :
2044                 case CertificateProblem.CertCN_NO_MATCH :
2045                     return IgnoreCertProblem.invalid_name;
2046
2047                 case CertificateProblem.CertINVALIDPOLICY :
2048                 case CertificateProblem.CertPURPOSE :
2049                     return IgnoreCertProblem.invalid_policy;
2050
2051                 case CertificateProblem.CertEXPIRED :
2052                     return IgnoreCertProblem.not_time_valid | IgnoreCertProblem.ctl_not_time_valid;
2053
2054                 case CertificateProblem.CertVALIDITYPERIODNESTING :
2055                     return IgnoreCertProblem.not_time_nested;
2056
2057                 case CertificateProblem.CertCHAINING :
2058                 case CertificateProblem.CertUNTRUSTEDCA :
2059                 case CertificateProblem.CertUNTRUSTEDROOT :
2060                     return IgnoreCertProblem.allow_unknown_ca;
2061
2062                 case CertificateProblem.CertREVOKED :
2063                 case CertificateProblem.CertREVOCATION_FAILURE :
2064                 case CertificateProblem.CryptNOREVOCATIONCHECK:
2065                 case CertificateProblem.CryptREVOCATIONOFFLINE:
2066                     return IgnoreCertProblem.all_rev_unknown;
2067
2068                 case CertificateProblem.CertROLE:
2069                 case CertificateProblem.TrustBASICCONSTRAINTS:
2070                     return IgnoreCertProblem.invalid_basic_constraints;
2071
2072                 case CertificateProblem.CertWRONG_USAGE :
2073                     return IgnoreCertProblem.wrong_usage;
2074
2075                 default:
2076                     return 0;
2077             }
2078         }
2079
2080
2081         private uint[] GetChainErrors(string hostName, X509Chain chain, ref bool fatalError)
2082         {
2083             fatalError = false;
2084             SafeFreeCertChain chainContext= new SafeFreeCertChain(chain.ChainContext);
2085             ArrayList certificateProblems = new ArrayList();
2086             unsafe {
2087                 uint status = 0;
2088                 ChainPolicyParameter cppStruct = new ChainPolicyParameter();
2089                 cppStruct.cbSize  = ChainPolicyParameter.StructSize;
2090                 cppStruct.dwFlags = 0;
2091
2092                 SSL_EXTRA_CERT_CHAIN_POLICY_PARA eppStruct = new SSL_EXTRA_CERT_CHAIN_POLICY_PARA(false);
2093                 cppStruct.pvExtraPolicyPara = &eppStruct;
2094
2095                 fixed (char* namePtr = hostName) {
2096                     if (ServicePointManager.CheckCertificateName){
2097                         eppStruct.pwszServerName = namePtr;
2098                     }
2099
2100                     while (true) {
2101                         status = VerifyChainPolicy(chainContext, ref cppStruct);
2102                         uint ignoreErrorMask = (uint)MapErrorCode(status);
2103
2104                         certificateProblems.Add(status);
2105
2106                         if (status == 0) {  // No more problems with the certificate?
2107                             break;          // Then break out of the callback loop
2108                         }
2109
2110                         if (ignoreErrorMask == 0) {  // Unrecognized error encountered
2111                             fatalError = true;
2112                             break;
2113                         }
2114                         else {
2115                             cppStruct.dwFlags |= ignoreErrorMask;
2116                             if ((CertificateProblem)status == CertificateProblem.CertCN_NO_MATCH && ServicePointManager.CheckCertificateName) {
2117                                 eppStruct.fdwChecks = IgnoreUnmatchedCN;
2118                             }
2119                         }
2120                     }
2121                 }
2122             }
2123
2124             return (uint[]) certificateProblems.ToArray(typeof(uint));
2125         }
2126
2127         internal bool CheckErrors(string hostName, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
2128         {
2129             if (sslPolicyErrors == 0)
2130                 return Accept(certificate, 0);
2131
2132             if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != 0)
2133                 return Accept(certificate, (int) CertificateProblem.CertCRITICAL); // ToDO, Define an appropriate enum entry
2134             else {
2135                 if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0 ||
2136                     (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0)
2137                 {
2138                     bool fatalError = false;
2139                     uint[] certificateProblems = GetChainErrors(hostName, chain, ref fatalError);
2140
2141                     if (fatalError) {
2142                         // By today design we cannot allow decider to ignore a fatal error.
2143                         // This error is fatal.
2144                         Accept(certificate, (int) SecurityStatus.InternalError);
2145                         return false;
2146                     }
2147
2148
2149                     if (certificateProblems.Length == 0)
2150                         return Accept(certificate, (int) CertificateProblem.OK);
2151
2152                     // Run each error through Accept().
2153                     foreach (uint error in certificateProblems)
2154                         if (!Accept(certificate, (int) error))
2155                             return false;
2156                 }
2157                 return true;
2158             }
2159         }
2160
2161 /* CONSIDER: Use this code when we switch to managed X509 API
2162         internal static int MapStatusToWin32Error(X509ChainStatusFlags status)
2163         {
2164             switch (status)
2165             {
2166             case X509ChainStatusFlags.NoError:       return CertificateProblem.OK;
2167             case X509ChainStatusFlags.NotTimeValid:  return CertificateProblem.CertEXPIRED;
2168             case X509ChainStatusFlags.NotTimeNested: return CertificateProblem.CertVALIDITYPERIODNESTING;
2169             case X509ChainStatusFlags.Revoked:       return CertificateProblem.CertREVOKED;
2170             case X509ChainStatusFlags.NotSignatureValid:return CertificateProblem.TrustCERTSIGNATURE;
2171             case X509ChainStatusFlags.NotValidForUsage: return CertificateProblem.CertWRONG_USAGE;
2172             case X509ChainStatusFlags.UntrustedRoot:    return CertificateProblem.CertUNTRUSTEDROOT;
2173             case X509ChainStatusFlags.RevocationStatusUnknown: return CertificateProblem.CryptNOREVOCATIONCHECK;
2174             case X509ChainStatusFlags.Cyclic:           return CertificateProblem.CertCHAINING;             //??
2175             case X509ChainStatusFlags.InvalidExtension: return CertificateProblem.CertCRITICAL;             //??
2176             case X509ChainStatusFlags.InvalidPolicyConstraints: return CertificateProblem.CertINVALIDPOLICY;
2177             case X509ChainStatusFlags.InvalidBasicConstraints: return CertificateProblem.TrustBASICCONSTRAINTS;
2178             case X509ChainStatusFlagsInvalidNameConstraints: return CertificateProblem.CertINVALIDNAME;
2179             case X509ChainStatusFlags.HasNotSupportedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2180             case X509ChainStatusFlags.HasNotDefinedNameConstraint:   return CertificateProblem.CertINVALIDNAME; //??
2181             case X509ChainStatusFlags.HasNotPermittedNameConstraint: return CertificateProblem.CertINVALIDNAME; //??
2182             case X509ChainStatusFlags.HasExcludedNameConstraint:     return CertificateProblem.CertINVALIDNAME; //??
2183             case X509ChainStatusFlags.PartialChain:         return CertificateProblem.CertCHAINING;             //??
2184             case X509ChainStatusFlags.CtlNotTimeValid:      return CertificateProblem.CertEXPIRED;
2185             case X509ChainStatusFlags.CtlNotSignatureValid: return CertificateProblem.TrustCERTSIGNATURE;
2186             case X509ChainStatusFlags.CtlNotValidForUsage:  return CertificateProblem.CertWRONG_USAGE;
2187             case X509ChainStatusFlags.OfflineRevocation:    return CertificateProblem.CryptREVOCATIONOFFLINE;
2188             case X509ChainStatusFlags.NoIssuanceChainPolicy:return CertificateProblem.CertINVALIDPOLICY;
2189             default: return (int) CertificateProblem.TrustSYSTEMERROR;  // unknown
2190             }
2191         }
2192 ***/
2193     }
2194     // Class implementing default certificate policy
2195     internal class DefaultCertPolicy : ICertificatePolicy {
2196         public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest request, int problem) {
2197             return problem == (int)CertificateProblem.OK;
2198         }
2199     }
2200 #endif // !FEATURE_PAL
2201
2202     internal enum TriState {
2203         Unspecified = -1,
2204         False = 0,
2205         True = 1
2206     }
2207
2208     internal enum DefaultPorts {
2209         DEFAULT_FTP_PORT = 21,
2210         DEFAULT_GOPHER_PORT = 70,
2211         DEFAULT_HTTP_PORT = 80,
2212         DEFAULT_HTTPS_PORT = 443,
2213         DEFAULT_NNTP_PORT = 119,
2214         DEFAULT_SMTP_PORT = 25,
2215         DEFAULT_TELNET_PORT = 23
2216     }
2217
2218     [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
2219     internal struct hostent {
2220         public IntPtr   h_name;
2221         public IntPtr   h_aliases;
2222         public short    h_addrtype;
2223         public short    h_length;
2224         public IntPtr   h_addr_list;
2225     }
2226
2227
2228     [StructLayout(LayoutKind.Sequential)]
2229     internal struct Blob {
2230         public int cbSize;
2231         public int pBlobData;
2232     }
2233
2234
2235     // This is only for internal code path i.e. TLS stream.
2236     // See comments on GetNextBuffer() method below.
2237     //
2238     internal class SplitWritesState
2239     {
2240         private const int c_SplitEncryptedBuffersSize = 64*1024;
2241         private BufferOffsetSize[] _UserBuffers;
2242         private int _Index;
2243         private int _LastBufferConsumed;
2244         private BufferOffsetSize[] _RealBuffers;
2245
2246         //
2247         internal SplitWritesState(BufferOffsetSize[] buffers)
2248         {
2249             _UserBuffers    = buffers;
2250             _LastBufferConsumed = 0;
2251             _Index          = 0;
2252             _RealBuffers = null;
2253         }
2254         //
2255         // Everything was handled
2256         //
2257         internal bool IsDone {
2258             get {
2259                 if (_LastBufferConsumed != 0)
2260                     return false;
2261
2262                 for (int index = _Index ;index < _UserBuffers.Length; ++index)
2263                     if (_UserBuffers[index].Size != 0)
2264                         return false;
2265
2266                 return true;
2267             }
2268         }
2269         // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
2270         // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
2271         // up to c_SplitEncryptedBuffersSize total.
2272         // Note that upon return from here EncryptBuffers() may additonally split the input
2273         // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
2274         //
2275         //  Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
2276         //
2277         //  Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
2278         //
2279         internal BufferOffsetSize[] GetNextBuffers()
2280         {
2281             int curIndex = _Index;
2282             int currentTotalSize = 0;
2283             int lastChunkSize = 0;
2284
2285             int  firstBufferConsumed = _LastBufferConsumed;
2286
2287             for ( ;_Index < _UserBuffers.Length; ++_Index)
2288             {
2289                 lastChunkSize = _UserBuffers[_Index].Size-_LastBufferConsumed;
2290
2291                 currentTotalSize += lastChunkSize;
2292
2293                 if (currentTotalSize > c_SplitEncryptedBuffersSize)
2294                 {
2295                     lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
2296                     currentTotalSize = c_SplitEncryptedBuffersSize;
2297                     break;
2298                 }
2299
2300                 lastChunkSize = 0;
2301                 _LastBufferConsumed = 0;
2302             }
2303
2304             // Are we done done?
2305             if (currentTotalSize == 0)
2306                 return null;
2307
2308              // Do all buffers fit the limit?
2309             if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
2310                 return _UserBuffers;
2311
2312             // We do have something to split and send out
2313             int buffersCount = lastChunkSize == 0? _Index-curIndex: _Index-curIndex+1;
2314
2315             if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
2316                 _RealBuffers = new BufferOffsetSize[buffersCount];
2317
2318             int j = 0;
2319             for (; curIndex < _Index; ++curIndex)
2320             {
2321                 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size-firstBufferConsumed, false);
2322                 firstBufferConsumed = 0;
2323             }
2324
2325             if (lastChunkSize != 0)
2326             {
2327                 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
2328                 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size)
2329                 {
2330                     ++_Index;
2331                     _LastBufferConsumed = 0;
2332                 }
2333             }
2334
2335             return _RealBuffers;
2336
2337         }
2338     }
2339 }