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