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