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