The Labs \ Source Viewer \ SSCLI \ System.Net \ HttpBehaviour

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Internal.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Net
  16. {
  17.     using System.IO;
  18.     using System.Reflection;
  19.     using System.Collections;
  20.     using System.Collections.Generic;
  21.     using System.Collections.Specialized;
  22.     using System.Globalization;
  23.     using System.Net.Sockets;
  24.     using System.Runtime.InteropServices;
  25.     using System.Runtime.Versioning;
  26.     using System.Security.Cryptography.X509Certificates;
  27.     using System.Text;
  28.     using System.Text.RegularExpressions;
  29.     using System.Security.Permissions;
  30.     using System.Diagnostics;
  31.     using System.Threading;
  32.     using System.Security.Principal;
  33.     using System.Security;
  34.     using System.Net.Security;
  35.     using System.Net.NetworkInformation;
  36.     using System.Runtime.Serialization;
  37.    
  38.     static internal class IntPtrHelper
  39.     {
  40. /*
  41.         //                                   
  42.         internal static IntPtr Add(IntPtr a, IntPtr b) {
  43.             return (IntPtr) ((long)a + (long)b);
  44.         }
  45.         */       
  46.         static internal IntPtr Add(IntPtr a, int b)
  47.         {
  48.             return (IntPtr)((long)a + (long)b);
  49.         }
  50.     }
  51.    
  52.     internal class InternalException : SystemException
  53.     {
  54.         internal InternalException()
  55.         {
  56.             GlobalLog.Assert("InternalException thrown.");
  57.         }
  58.        
  59.         internal InternalException(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(serializationInfo, streamingContext)
  60.         {
  61.         }
  62.     }
  63.    
  64.     static internal class NclUtilities
  65.     {
  66.         /// <devdoc>
  67.         /// <para>
  68.         /// Indicates true if the threadpool is low on threads,
  69.         /// in this case we need to refuse to start new requests,
  70.         /// and avoid blocking.
  71.         /// </para>
  72.         /// </devdoc>
  73.         static internal bool IsThreadPoolLow()
  74.         {
  75.            
  76.             int workerThreads;
  77.             int completionPortThreads;
  78.             ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
  79.            
  80.             return workerThreads < 2 || completionPortThreads < 2;
  81.         }
  82.        
  83.         static internal bool HasShutdownStarted {
  84.             get { return Environment.HasShutdownStarted || AppDomain.CurrentDomain.IsFinalizingForUnload(); }
  85.         }
  86.        
  87.        
  88.         // ContextRelativeDemand
  89.         // Allows easily demanding a permission against a given ExecutionContext.
  90.         // Have requested the CLR to provide this method on ExecutionContext.
  91.         private static ContextCallback s_ContextRelativeDemandCallback;
  92.        
  93.         static internal ContextCallback ContextRelativeDemandCallback {
  94.             get {
  95.                 if (s_ContextRelativeDemandCallback == null)
  96.                     s_ContextRelativeDemandCallback = new ContextCallback(DemandCallback);
  97.                 return s_ContextRelativeDemandCallback;
  98.             }
  99.         }
  100.        
  101.         private static void DemandCallback(object state)
  102.         {
  103.             ((CodeAccessPermission)state).Demand();
  104.         }
  105.        
  106.         // This is for checking if a hostname probably refers to this machine without going to DNS.
  107.         static internal bool GuessWhetherHostIsLoopback(string host)
  108.         {
  109.             string hostLower = host.ToLowerInvariant();
  110.             if (hostLower == "localhost" || hostLower == "loopback") {
  111.                 return true;
  112.             }
  113.            
  114.             return false;
  115.         }
  116.        
  117.         static internal bool IsFatal(Exception exception)
  118.         {
  119.             return exception != null && (exception is OutOfMemoryException || exception is StackOverflowException || exception is ThreadAbortException);
  120.         }
  121.        
  122.         // Need a fast cached list of local addresses for internal use.
  123.         private static IPAddress[] _LocalAddresses;
  124.         private static object _LocalAddressesLock;
  125.        
  126.         private const int HostNameBufferLength = 256;
  127.         static internal string _LocalDomainName;
  128.        
  129.         // Copied from the old version of DNS.cs
  130.         // Returns a list of our local addresses by calling gethostbyname with null.
  131.         //
  132.         private static IPHostEntry GetLocalHost()
  133.         {
  134.             //
  135.             // IPv6 Changes: If IPv6 is enabled, we can't simply use the
  136.             // old IPv4 gethostbyname(null). Instead we need
  137.             // to do a more complete lookup.
  138.             //
  139.             if (Socket.SupportsIPv6) {
  140.                 //
  141.                 // IPv6 enabled: use getaddrinfo() of the local host name
  142.                 // to obtain this information. Need to get the machines
  143.                 // name as well - do that here so that we don't need to
  144.                 // Assert DNS permissions.
  145.                 //
  146.                 StringBuilder hostname = new StringBuilder(HostNameBufferLength);
  147.                 SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.gethostname(hostname, HostNameBufferLength);
  148.                
  149.                 if (errorCode != SocketError.Success) {
  150.                     throw new SocketException();
  151.                 }
  152.                
  153.                 return Dns.GetHostByName(hostname.ToString());
  154.             }
  155.             else {
  156.                 //
  157.                 // IPv6 disabled: use gethostbyname() to obtain information.
  158.                 //
  159.                 IntPtr nativePointer = UnsafeNclNativeMethods.OSSOCK.gethostbyname(null);
  160.                
  161.                 if (nativePointer == IntPtr.Zero) {
  162.                     throw new SocketException();
  163.                 }
  164.                
  165.                 return Dns.NativeToHostEntry(nativePointer);
  166.             }
  167.            
  168.         }
  169.         // GetLocalHost
  170.         static internal IPAddress[] LocalAddresses {
  171.             get {
  172.                 IPAddress[] local = _LocalAddresses;
  173.                 if (local != null) {
  174.                     return local;
  175.                 }
  176.                
  177.                 lock (LocalAddressesLock) {
  178.                     local = _LocalAddresses;
  179.                     if (local != null) {
  180.                         return local;
  181.                     }
  182.                    
  183.                     List<IPAddress> localList = new List<IPAddress>();
  184.                    
  185.                     try {
  186.                         IPHostEntry hostEntry = GetLocalHost();
  187.                         if (hostEntry != null) {
  188.                             if (hostEntry.HostName != null) {
  189.                                 int dot = hostEntry.HostName.IndexOf('.');
  190.                                 if (dot != -1) {
  191.                                     _LocalDomainName = hostEntry.HostName.Substring(dot);
  192.                                 }
  193.                             }
  194.                            
  195.                             IPAddress[] ipAddresses = hostEntry.AddressList;
  196.                             if (ipAddresses != null) {
  197.                                 foreach (IPAddress ipAddress in ipAddresses) {
  198.                                     localList.Add(ipAddress);
  199.                                 }
  200.                             }
  201.                         }
  202.                     }
  203.                     catch {
  204.                     }
  205.                    
  206.                     local = new IPAddress[localList.Count];
  207.                     int index = 0;
  208.                     foreach (IPAddress ipAddress in localList) {
  209.                         local[index] = ipAddress;
  210.                         index++;
  211.                     }
  212.                     _LocalAddresses = local;
  213.                    
  214.                     return local;
  215.                 }
  216.             }
  217.         }
  218.        
  219.         static internal bool IsAddressLocal(IPAddress ipAddress)
  220.         {
  221.             IPAddress[] localAddresses = NclUtilities.LocalAddresses;
  222.             for (int i = 0; i < localAddresses.Length; i++) {
  223.                 if (ipAddress.Equals(localAddresses[i], false)) {
  224.                     return true;
  225.                 }
  226.             }
  227.             return false;
  228.         }
  229.        
  230.         private static object LocalAddressesLock {
  231.             get {
  232.                 if (_LocalAddressesLock == null) {
  233.                     Interlocked.CompareExchange(ref _LocalAddressesLock, new object(), null);
  234.                 }
  235.                 return _LocalAddressesLock;
  236.             }
  237.         }
  238.     }
  239.    
  240.     static internal class NclConstants
  241.     {
  242.         static internal readonly object Sentinel = new object();
  243.         static internal readonly object[] EmptyObjectArray = new object[0];
  244.         static internal readonly Uri[] EmptyUriArray = new Uri[0];
  245.        
  246.         static internal readonly byte[] CRLF = new byte[] {(byte)'\r', (byte)'\n'};
  247.         static internal readonly byte[] ChunkTerminator = new byte[] {(byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n'};
  248.     }
  249.    
  250.     //
  251.     // A simple sync point, useful for deferring work. Just an int value with helper methods.
  252.     //
  253.     // The two events being synchronized are the "Triggering" event and the "Completing" event. The Triggering event
  254.     // marks the gate as being active; the first subsequent Completing event handles the action.
  255.     //
  256.     // First, a thread calls Trigger() to set the trigger on the gate. This means it needs some work to be done, but only
  257.     // after another operation (the Completing event) finishes. If Trigger() returns false, the Completing event already
  258.     // happened. When the Completing event occurs, that thread calls Complete(). It returns true if the gate has been
  259.     // previously triggered and the caller is the first one to complete it. The caller should then handle the pending work item.
  260.     //
  261.     // StartTrigger()/FinishTrigger() can be used instead of Trigger() if the triggering thread needs to set up some state
  262.     // (e.g. the pending work item). It will block Complete() in a spin-lock.
  263.     //
  264.     internal struct InterlockedGate
  265.     {
  266.         private int m_State;
  267.        
  268.         internal const int Open = 0;
  269.         // Initial state of gate.
  270.         internal const int Held = 1;
  271.         // Gate is being actively held by a thread - indeterminate state.
  272.         internal const int Triggered = 2;
  273.         // The triggering event has occurred.
  274.         internal const int Closed = 3;
  275.         // The gated event is done.
  276.         #if DEBUG
  277. /* Consider removing
  278.         internal int State
  279.         {
  280.             get
  281.             {
  282.                 return m_State;
  283.             }
  284.         }
  285.         */       
  286.         #endif
  287.        
  288.         // Only call when all threads are guaranteed to be done with the gate.
  289.         internal void Reset()
  290.         {
  291.             m_State = Open;
  292.         }
  293.        
  294.         // Returns false if the gate is already closed or triggered. If exclusive is true, throws if the gate is already
  295.         // triggered.
  296.         internal bool Trigger(bool exclusive)
  297.         {
  298.             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Open);
  299.             if (exclusive && (gate == Held || gate == Triggered)) {
  300.                 GlobalLog.Assert("InterlockedGate::Trigger", "Gate already triggered.");
  301.                 throw new InternalException();
  302.             }
  303.             return gate == Open;
  304.         }
  305.        
  306.         // Use StartTrigger() and FinishTrigger() to trigger the gate as a two step operation. This is useful to set up an invariant
  307.         // that must be ready by the time another thread closes the gate. Do not block between StartTrigger() and FinishTrigger(), just
  308.         // set up your state to be consistent. If this method returns true, FinishTrigger() *must* be called to avoid deadlock - do
  309.         // it in a finally.
  310.         //
  311.         // Returns false if the gate is already closed or triggered. If exclusive is true, throws if the gate is already
  312.         // triggered.
  313.         internal bool StartTrigger(bool exclusive)
  314.         {
  315.             int gate = Interlocked.CompareExchange(ref m_State, Held, Open);
  316.             if (exclusive && (gate == Held || gate == Triggered)) {
  317.                 GlobalLog.Assert("InterlockedGate::StartTrigger", "Gate already triggered.");
  318.                 throw new InternalException();
  319.             }
  320.             return gate == Open;
  321.         }
  322.        
  323.         // Gate must be held by StartTrigger().
  324.         internal void FinishTrigger()
  325.         {
  326.             int gate = Interlocked.CompareExchange(ref m_State, Triggered, Held);
  327.             if (gate != Held) {
  328.                 GlobalLog.Assert("InterlockedGate::FinishTrigger", "Gate not held.");
  329.                 throw new InternalException();
  330.             }
  331.         }
  332.        
  333.         // Returns false if the gate had never been triggered or is already closed.
  334.         internal bool Complete()
  335.         {
  336.             int gate;
  337.            
  338.             // Spin while the gate is being held, allowing the other thread to set invariants up.
  339.             while ((gate = Interlocked.CompareExchange(ref m_State, Closed, Triggered)) != Triggered) {
  340.                 if (gate == Closed) {
  341.                     return false;
  342.                 }
  343.                
  344.                 if (gate == Open) {
  345.                     if (Interlocked.CompareExchange(ref m_State, Closed, Open) == Open) {
  346.                         return false;
  347.                     }
  348.                    
  349.                     continue;
  350.                 }
  351.                
  352.                 // gate == Held
  353.                 Thread.SpinWait(1);
  354.             }
  355.            
  356.             return true;
  357.         }
  358.     }
  359.    
  360.    
  361.    
  362.    
  363.    
  364.    
  365.     //
  366.     // support class for Validation related stuff.
  367.     //
  368.     static internal class ValidationHelper
  369.     {
  370.        
  371.         public static string[] EmptyArray = new string[0];
  372.        
  373.         static internal readonly char[] InvalidMethodChars = new char[] {' ', '\r', '\n', '\t'};
  374.        
  375.         // invalid characters that cannot be found in a valid method-verb or http header
  376.         static internal readonly char[] InvalidParamChars = new char[] {'(', ')', '<', '>', '@', ',', ';', ':', '\\', '"',
  377.         '\'', '/', '[', ']', '?', '=', '{', '}', ' ', '\t',
  378.         '\r', '\n'};
  379.        
  380.         public static string[] MakeEmptyArrayNull(string[] stringArray)
  381.         {
  382.             if (stringArray == null || stringArray.Length == 0) {
  383.                 return null;
  384.             }
  385.             else {
  386.                 return stringArray;
  387.             }
  388.         }
  389.        
  390.         public static string MakeStringNull(string stringValue)
  391.         {
  392.             if (stringValue == null || stringValue.Length == 0) {
  393.                 return null;
  394.             }
  395.             else {
  396.                 return stringValue;
  397.             }
  398.         }
  399.        
  400. /*
  401.         //                                   
  402.         public static string MakeStringEmpty(string stringValue) {
  403.             if ( stringValue == null || stringValue.Length == 0) {
  404.                 return String.Empty;
  405.             } else {
  406.                 return stringValue;
  407.             }
  408.         }
  409.         */       
  410.        
  411.        
  412.         public static string ExceptionMessage(Exception exception)
  413.         {
  414.             if (exception == null) {
  415.                 return string.Empty;
  416.             }
  417.             if (exception.InnerException == null) {
  418.                 return exception.Message;
  419.             }
  420.             return exception.Message + " (" + ExceptionMessage(exception.InnerException) + ")";
  421.         }
  422.        
  423.         public static string ToString(object objectValue)
  424.         {
  425.             if (objectValue == null) {
  426.                 return "(null)";
  427.             }
  428.             else if (objectValue is string && ((string)objectValue).Length == 0) {
  429.                 return "(string.empty)";
  430.             }
  431.             else if (objectValue is Exception) {
  432.                 return ExceptionMessage(objectValue as Exception);
  433.             }
  434.             else if (objectValue is IntPtr) {
  435.                 return "0x" + ((IntPtr)objectValue).ToString("x");
  436.             }
  437.             else {
  438.                 return objectValue.ToString();
  439.             }
  440.         }
  441.         public static string HashString(object objectValue)
  442.         {
  443.             if (objectValue == null) {
  444.                 return "(null)";
  445.             }
  446.             else if (objectValue is string && ((string)objectValue).Length == 0) {
  447.                 return "(string.empty)";
  448.             }
  449.             else {
  450.                 return objectValue.GetHashCode().ToString(NumberFormatInfo.InvariantInfo);
  451.             }
  452.         }
  453.        
  454.         public static bool IsInvalidHttpString(string stringValue)
  455.         {
  456.             return stringValue.IndexOfAny(InvalidParamChars) != -1;
  457.         }
  458.        
  459.         public static bool IsBlankString(string stringValue)
  460.         {
  461.             return stringValue == null || stringValue.Length == 0;
  462.         }
  463.        
  464. /*
  465.         //                                   
  466.         public static bool ValidateUInt32(long address) {
  467.             // on false, API should throw new ArgumentOutOfRangeException("address");
  468.             return address>=0x00000000 && address<=0xFFFFFFFF;
  469.         }
  470.         */       
  471.        
  472.         public static bool ValidateTcpPort(int port)
  473.         {
  474.             // on false, API should throw new ArgumentOutOfRangeException("port");
  475.             return port >= IPEndPoint.MinPort && port <= IPEndPoint.MaxPort;
  476.         }
  477.        
  478.         public static bool ValidateRange(int actual, int fromAllowed, int toAllowed)
  479.         {
  480.             // on false, API should throw new ArgumentOutOfRangeException("argument");
  481.             return actual >= fromAllowed && actual <= toAllowed;
  482.         }
  483.        
  484.         /*
  485.         //                                   
  486.         public static bool ValidateRange(long actual, long fromAllowed, long toAllowed) {
  487.             // on false, API should throw new ArgumentOutOfRangeException("argument");
  488.             return actual>=fromAllowed && actual<=toAllowed;
  489.         }
  490.         */       
  491.     }
  492.    
  493.     static internal class ExceptionHelper
  494.     {
  495.         static internal readonly WebPermission WebPermissionUnrestricted = new WebPermission(NetworkAccess.Connect);
  496.         static internal readonly SecurityPermission UnmanagedPermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
  497.         static internal readonly SocketPermission UnrestrictedSocketPermission = new SocketPermission(PermissionState.Unrestricted);
  498.         static internal readonly SecurityPermission InfrastructurePermission = new SecurityPermission(SecurityPermissionFlag.Infrastructure);
  499.         static internal readonly SecurityPermission ControlPolicyPermission = new SecurityPermission(SecurityPermissionFlag.ControlPolicy);
  500.         static internal readonly SecurityPermission ControlPrincipalPermission = new SecurityPermission(SecurityPermissionFlag.ControlPrincipal);
  501.        
  502.         static internal NotImplementedException MethodNotImplementedException {
  503.             get { return new NotImplementedException(SR.GetString(SR.net_MethodNotImplementedException)); }
  504.         }
  505.        
  506.         static internal NotImplementedException PropertyNotImplementedException {
  507.             get { return new NotImplementedException(SR.GetString(SR.net_PropertyNotImplementedException)); }
  508.         }
  509.        
  510.         static internal NotSupportedException MethodNotSupportedException {
  511.             get { return new NotSupportedException(SR.GetString(SR.net_MethodNotSupportedException)); }
  512.         }
  513.        
  514.         static internal NotSupportedException PropertyNotSupportedException {
  515.             get { return new NotSupportedException(SR.GetString(SR.net_PropertyNotSupportedException)); }
  516.         }
  517.        
  518.         static internal WebException IsolatedException {
  519.             get { return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.KeepAliveFailure), WebExceptionStatus.KeepAliveFailure, WebExceptionInternalStatus.Isolated, null); }
  520.         }
  521.        
  522.         static internal WebException RequestAbortedException {
  523.             get { return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled); }
  524.         }
  525.        
  526.         static internal UriFormatException BadSchemeException {
  527.             get { return new UriFormatException(SR.GetString(SR.net_uri_BadScheme)); }
  528.         }
  529.        
  530.         static internal UriFormatException BadAuthorityException {
  531.             get { return new UriFormatException(SR.GetString(SR.net_uri_BadAuthority)); }
  532.         }
  533.        
  534.         static internal UriFormatException EmptyUriException {
  535.             get { return new UriFormatException(SR.GetString(SR.net_uri_EmptyUri)); }
  536.         }
  537.        
  538.         static internal UriFormatException SchemeLimitException {
  539.             get { return new UriFormatException(SR.GetString(SR.net_uri_SchemeLimit)); }
  540.         }
  541.        
  542.         static internal UriFormatException SizeLimitException {
  543.             get { return new UriFormatException(SR.GetString(SR.net_uri_SizeLimit)); }
  544.         }
  545.        
  546.         static internal UriFormatException MustRootedPathException {
  547.             get { return new UriFormatException(SR.GetString(SR.net_uri_MustRootedPath)); }
  548.         }
  549.        
  550.         static internal UriFormatException BadHostNameException {
  551.             get { return new UriFormatException(SR.GetString(SR.net_uri_BadHostName)); }
  552.         }
  553.        
  554.         static internal UriFormatException BadPortException {
  555.             get { return new UriFormatException(SR.GetString(SR.net_uri_BadPort)); }
  556.         }
  557.        
  558.         static internal UriFormatException BadAuthorityTerminatorException {
  559.             get { return new UriFormatException(SR.GetString(SR.net_uri_BadAuthorityTerminator)); }
  560.         }
  561.        
  562.         static internal UriFormatException BadFormatException {
  563.             get { return new UriFormatException(SR.GetString(SR.net_uri_BadFormat)); }
  564.         }
  565.        
  566.         static internal UriFormatException CannotCreateRelativeException {
  567.             get { return new UriFormatException(SR.GetString(SR.net_uri_CannotCreateRelative)); }
  568.         }
  569.        
  570.         static internal WebException CacheEntryNotFoundException {
  571.             get { return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.CacheEntryNotFound), WebExceptionStatus.CacheEntryNotFound); }
  572.         }
  573.        
  574.         static internal WebException RequestProhibitedByCachePolicyException {
  575.             get { return new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestProhibitedByCachePolicy), WebExceptionStatus.RequestProhibitedByCachePolicy); }
  576.         }
  577.     }
  578.    
  579.    
  580.     //
  581.     // WebRequestPrefixElement
  582.     //
  583.     // This is an element of the prefix list. It contains the prefix and the
  584.     // interface to be called to create a request for that prefix.
  585.     //
  586.    
  587.     /// <devdoc>
  588.     /// <para>[To be supplied.]</para>
  589.     /// </devdoc>
  590.     // internal class WebRequestPrefixElement {
  591.     internal class WebRequestPrefixElement
  592.     {
  593.        
  594.         /// <devdoc>
  595.         /// <para>[To be supplied.]</para>
  596.         /// </devdoc>
  597.         public string Prefix;
  598.         /// <devdoc>
  599.         /// <para>[To be supplied.]</para>
  600.         /// </devdoc>
  601.         internal IWebRequestCreate creator;
  602.         /// <devdoc>
  603.         /// <para>[To be supplied.]</para>
  604.         /// </devdoc>
  605.         internal Type creatorType;
  606.        
  607.         public IWebRequestCreate Creator {
  608.             get {
  609.                 if (creator == null && creatorType != null) {
  610.                     lock (this) {
  611.                         if (creator == null) {
  612.                                 // Binder
  613.                                 // no arguments
  614.                             creator = (IWebRequestCreate)Activator.CreateInstance(creatorType, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, new object[0], CultureInfo.InvariantCulture);
  615.                         }
  616.                     }
  617.                 }
  618.                
  619.                 return creator;
  620.             }
  621.            
  622.             set { creator = value; }
  623.         }
  624.        
  625.         public WebRequestPrefixElement(string P, Type creatorType)
  626.         {
  627.             // verify that its of the proper type of IWebRequestCreate
  628.             if (!typeof(IWebRequestCreate).IsAssignableFrom(creatorType)) {
  629.                 throw new InvalidCastException(SR.GetString(SR.net_invalid_cast, creatorType.AssemblyQualifiedName, "IWebRequestCreate"));
  630.             }
  631.            
  632.             Prefix = P;
  633.             this.creatorType = creatorType;
  634.         }
  635.        
  636.         /// <devdoc>
  637.         /// <para>[To be supplied.]</para>
  638.         /// </devdoc>
  639.         public WebRequestPrefixElement(string P, IWebRequestCreate C)
  640.         {
  641.             Prefix = P;
  642.             Creator = C;
  643.         }
  644.        
  645.     }
  646.     // class PrefixListElement
  647.    
  648.     //
  649.     // HttpRequestCreator.
  650.     //
  651.     // This is the class that we use to create HTTP and HTTPS requests.
  652.     //
  653.    
  654.     internal class HttpRequestCreator : IWebRequestCreate
  655.     {
  656.        
  657. /*++
  658.         Create - Create an HttpWebRequest.
  659.             This is our method to create an HttpWebRequest. We register
  660.             for HTTP and HTTPS Uris, and this method is called when a request
  661.             needs to be created for one of those.
  662.             Input:
  663.                     Uri            - Uri for request being created.
  664.             Returns:
  665.                     The newly created HttpWebRequest.
  666.         --*/       
  667.        
  668.         public WebRequest Create(Uri Uri)
  669.         {
  670.             //
  671.             // Note, DNS permissions check will not happen on WebRequest
  672.             //
  673.             return new HttpWebRequest(Uri, null);
  674.         }
  675.        
  676.     }
  677.     // class HttpRequestCreator
  678.     //
  679.     // CoreResponseData - Used to store result of HTTP header parsing and
  680.     // response parsing. Also Contains new stream to use, and
  681.     // is used as core of new Response
  682.     //
  683.     internal class CoreResponseData
  684.     {
  685.        
  686.         // Status Line Response Values
  687.         public HttpStatusCode m_StatusCode;
  688.         public string m_StatusDescription;
  689.         public bool m_IsVersionHttp11;
  690.        
  691.         // Content Length needed for semantics, -1 if chunked
  692.         public long m_ContentLength;
  693.        
  694.         // Response Headers
  695.         public WebHeaderCollection m_ResponseHeaders;
  696.        
  697.         // ConnectStream - for reading actual data
  698.         public Stream m_ConnectStream;
  699.        
  700.         internal CoreResponseData Clone()
  701.         {
  702.             CoreResponseData cloneResponseData = new CoreResponseData();
  703.             cloneResponseData.m_StatusCode = m_StatusCode;
  704.             cloneResponseData.m_StatusDescription = m_StatusDescription;
  705.             cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11;
  706.             cloneResponseData.m_ContentLength = m_ContentLength;
  707.             cloneResponseData.m_ResponseHeaders = m_ResponseHeaders;
  708.             cloneResponseData.m_ConnectStream = m_ConnectStream;
  709.             return cloneResponseData;
  710.         }
  711.        
  712.     }
  713.    
  714.    
  715. /*++
  716.     StreamChunkBytes - A class to read a chunk stream from a ConnectStream.
  717.     A simple little value class that implements the IReadChunkBytes
  718.     interface.
  719.     --*/   
  720.     internal class StreamChunkBytes : IReadChunkBytes
  721.     {
  722.        
  723.         public ConnectStream ChunkStream;
  724.         public int BytesRead = 0;
  725.         public int TotalBytesRead = 0;
  726.         private byte PushByte;
  727.         private bool HavePush;
  728.        
  729.         public StreamChunkBytes(ConnectStream connectStream)
  730.         {
  731.             ChunkStream = connectStream;
  732.             return;
  733.         }
  734.        
  735.         public int NextByte {
  736.             get {
  737.                 if (HavePush) {
  738.                     HavePush = false;
  739.                     return PushByte;
  740.                 }
  741.                
  742.                 return ChunkStream.ReadSingleByte();
  743.             }
  744.             set {
  745.                 PushByte = (byte)value;
  746.                 HavePush = true;
  747.             }
  748.         }
  749.        
  750.     }
  751.     // class StreamChunkBytes
  752.    
  753.     internal delegate bool HttpAbortDelegate(HttpWebRequest request, WebException webException);
  754.    
  755.     //
  756.     // this class contains known header names
  757.     //
  758.    
  759.     static internal class HttpKnownHeaderNames
  760.     {
  761.        
  762.         public const string CacheControl = "Cache-Control";
  763.         public const string Connection = "Connection";
  764.         public const string Date = "Date";
  765.         public const string KeepAlive = "Keep-Alive";
  766.         public const string Pragma = "Pragma";
  767.         public const string ProxyConnection = "Proxy-Connection";
  768.         public const string Trailer = "Trailer";
  769.         public const string TransferEncoding = "Transfer-Encoding";
  770.         public const string Upgrade = "Upgrade";
  771.         public const string Via = "Via";
  772.         public const string Warning = "Warning";
  773.         public const string ContentLength = "Content-Length";
  774.         public const string ContentType = "Content-Type";
  775.         public const string ContentEncoding = "Content-Encoding";
  776.         public const string ContentLanguage = "Content-Language";
  777.         public const string ContentLocation = "Content-Location";
  778.         public const string ContentRange = "Content-Range";
  779.         public const string Expires = "Expires";
  780.         public const string LastModified = "Last-Modified";
  781.         public const string Age = "Age";
  782.         public const string Location = "Location";
  783.         public const string ProxyAuthenticate = "Proxy-Authenticate";
  784.         public const string RetryAfter = "Retry-After";
  785.         public const string Server = "Server";
  786.         public const string SetCookie = "Set-Cookie";
  787.         public const string SetCookie2 = "Set-Cookie2";
  788.         public const string Vary = "Vary";
  789.         public const string WWWAuthenticate = "WWW-Authenticate";
  790.         public const string Accept = "Accept";
  791.         public const string AcceptCharset = "Accept-Charset";
  792.         public const string AcceptEncoding = "Accept-Encoding";
  793.         public const string AcceptLanguage = "Accept-Language";
  794.         public const string Authorization = "Authorization";
  795.         public const string Cookie = "Cookie";
  796.         public const string Cookie2 = "Cookie2";
  797.         public const string Expect = "Expect";
  798.         public const string From = "From";
  799.         public const string Host = "Host";
  800.         public const string IfMatch = "If-Match";
  801.         public const string IfModifiedSince = "If-Modified-Since";
  802.         public const string IfNoneMatch = "If-None-Match";
  803.         public const string IfRange = "If-Range";
  804.         public const string IfUnmodifiedSince = "If-Unmodified-Since";
  805.         public const string MaxForwards = "Max-Forwards";
  806.         public const string ProxyAuthorization = "Proxy-Authorization";
  807.         public const string Referer = "Referer";
  808.         public const string Range = "Range";
  809.         public const string UserAgent = "User-Agent";
  810.         public const string ContentMD5 = "Content-MD5";
  811.         public const string ETag = "ETag";
  812.         public const string TE = "TE";
  813.         public const string Allow = "Allow";
  814.         public const string AcceptRanges = "Accept-Ranges";
  815.         public const string P3P = "P3P";
  816.         public const string XPoweredBy = "X-Powered-By";
  817.         public const string XAspNetVersion = "X-AspNet-Version";
  818.     }
  819.    
  820.     /// <devdoc>
  821.     /// <para>
  822.     /// Represents the method that will notify callers when a continue has been
  823.     /// received by the client.
  824.     /// </para>
  825.     /// </devdoc>
  826.     // Delegate type for us to notify callers when we receive a continue
  827.     public delegate void HttpContinueDelegate(int StatusCode, WebHeaderCollection httpHeaders);
  828.    
  829.     //
  830.     // HttpWriteMode - used to control the way in which an entity Body is posted.
  831.     //
  832.     enum HttpWriteMode
  833.     {
  834.         Unknown = 0,
  835.         ContentLength = 1,
  836.         Chunked = 2,
  837.         Buffer = 3,
  838.         None = 4
  839.     }
  840.    
  841.     // Used by Request to notify Connection that we are no longer holding the Connection (for NTLM connection sharing)
  842.     delegate void UnlockConnectionDelegate();
  843.    
  844.     enum HttpBehaviour : byte
  845.     {
  846.         Unknown = 0,
  847.         HTTP10 = 1,
  848.         HTTP11PartiallyCompliant = 2,
  849.         HTTP11 = 3
  850.     }
  851.    
  852.     internal enum HttpProcessingResult
  853.     {
  854.         Continue = 0,
  855.         ReadWait = 1,
  856.         WriteWait = 2
  857.     }
  858.    
  859.     //
  860.     // HttpVerb - used to define various per Verb Properties
  861.     //
  862.    
  863.     //
  864.     // Note - this is a place holder for Verb properties,
  865.     // the following two bools can most likely be combined into
  866.     // a single Enum type. And the Verb can be incorporated.
  867.     //
  868.     class KnownHttpVerb
  869.     {
  870.         internal string Name;
  871.         // verb name
  872.         internal bool RequireContentBody;
  873.         // require content body to be sent
  874.         internal bool ContentBodyNotAllowed;
  875.         // not allowed to send content body
  876.         internal bool ConnectRequest;
  877.         // special semantics for a connect request
  878.         internal bool ExpectNoContentResponse;
  879.         // response will not have content body
  880.         internal KnownHttpVerb(string name, bool requireContentBody, bool contentBodyNotAllowed, bool connectRequest, bool expectNoContentResponse)
  881.         {
  882.             Name = name;
  883.             RequireContentBody = requireContentBody;
  884.             ContentBodyNotAllowed = contentBodyNotAllowed;
  885.             ConnectRequest = connectRequest;
  886.             ExpectNoContentResponse = expectNoContentResponse;
  887.         }
  888.        
  889.         // Force an an init, before we use them
  890.         private static ListDictionary NamedHeaders;
  891.        
  892.         // known verbs
  893.         static internal KnownHttpVerb Get;
  894.         static internal KnownHttpVerb Connect;
  895.         static internal KnownHttpVerb Head;
  896.         static internal KnownHttpVerb Put;
  897.         static internal KnownHttpVerb Post;
  898.         static internal KnownHttpVerb MkCol;
  899.        
  900.         //
  901.         // InitializeKnownVerbs - Does basic init for this object,
  902.         // such as creating defaultings and filling them
  903.         //
  904.         static KnownHttpVerb()
  905.         {
  906.             NamedHeaders = new ListDictionary(CaseInsensitiveAscii.StaticInstance);
  907.             Get = new KnownHttpVerb("GET", false, true, false, false);
  908.             Connect = new KnownHttpVerb("CONNECT", false, true, true, false);
  909.             Head = new KnownHttpVerb("HEAD", false, true, false, true);
  910.             Put = new KnownHttpVerb("PUT", true, false, false, false);
  911.             Post = new KnownHttpVerb("POST", true, false, false, false);
  912.             MkCol = new KnownHttpVerb("MKCOL", false, false, false, false);
  913.             NamedHeaders[Get.Name] = Get;
  914.             NamedHeaders[Connect.Name] = Connect;
  915.             NamedHeaders[Head.Name] = Head;
  916.             NamedHeaders[Put.Name] = Put;
  917.             NamedHeaders[Post.Name] = Post;
  918.             NamedHeaders[MkCol.Name] = MkCol;
  919.         }
  920.        
  921.         public bool Equals(KnownHttpVerb verb)
  922.         {
  923.             return this == verb || string.Compare(Name, verb.Name, StringComparison.OrdinalIgnoreCase) == 0;
  924.         }
  925.        
  926.         public static KnownHttpVerb Parse(string name)
  927.         {
  928.             KnownHttpVerb knownHttpVerb = NamedHeaders[name] as KnownHttpVerb;
  929.             if (knownHttpVerb == null) {
  930.                 // unknown verb, default behaviour
  931.                 knownHttpVerb = new KnownHttpVerb(name, false, false, false, false);
  932.             }
  933.             return knownHttpVerb;
  934.         }
  935.     }
  936.    
  937.    
  938.     //
  939.     // HttpProtocolUtils - A collection of utility functions for HTTP usage.
  940.     //
  941.    
  942.     internal class HttpProtocolUtils
  943.     {
  944.        
  945.         private HttpProtocolUtils()
  946.         {
  947.         }
  948.        
  949.         //
  950.         // extra buffers for build/parsing, recv/send HTTP data,
  951.         // at some point we should consolidate
  952.         //
  953.        
  954.        
  955.         // parse String to DateTime format.
  956.         static internal DateTime string2date(string S)
  957.         {
  958.             DateTime dtOut;
  959.             if (HttpDateParse.ParseHttpDate(S, out dtOut)) {
  960.                 return dtOut;
  961.             }
  962.             else {
  963.                 throw new ProtocolViolationException(SR.GetString(SR.net_baddate));
  964.             }
  965.            
  966.         }
  967.        
  968.         // convert Date to String using RFC 1123 pattern
  969.         static internal string date2string(DateTime D)
  970.         {
  971.             DateTimeFormatInfo dateFormat = new DateTimeFormatInfo();
  972.             return D.ToUniversalTime().ToString("R", dateFormat);
  973.         }
  974.     }
  975.    
  976.    
  977.     internal enum TriState
  978.     {
  979.         Unspecified = -1,
  980.         False = 0,
  981.         True = 1
  982.     }
  983.    
  984.     internal enum DefaultPorts
  985.     {
  986.         DEFAULT_FTP_PORT = 21,
  987.         DEFAULT_GOPHER_PORT = 70,
  988.         DEFAULT_HTTP_PORT = 80,
  989.         DEFAULT_HTTPS_PORT = 443,
  990.         DEFAULT_NNTP_PORT = 119,
  991.         DEFAULT_SMTP_PORT = 25,
  992.         DEFAULT_TELNET_PORT = 23
  993.     }
  994.    
  995.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  996.     internal struct hostent
  997.     {
  998.         public IntPtr h_name;
  999.         public IntPtr h_aliases;
  1000.         public short h_addrtype;
  1001.         public short h_length;
  1002.         public IntPtr h_addr_list;
  1003.     }
  1004.    
  1005.    
  1006.     [StructLayout(LayoutKind.Sequential)]
  1007.     internal struct Blob
  1008.     {
  1009.         public int cbSize;
  1010.         public int pBlobData;
  1011.     }
  1012.    
  1013.    
  1014.     // This is only for internal code path i.e. TLS stream.
  1015.     // See comments on GetNextBuffer() method below.
  1016.     //
  1017.     internal class SplitWritesState
  1018.     {
  1019.         private const int c_SplitEncryptedBuffersSize = 64 * 1024;
  1020.         private BufferOffsetSize[] _UserBuffers;
  1021.         private int _Index;
  1022.         private int _LastBufferConsumed;
  1023.         private BufferOffsetSize[] _RealBuffers;
  1024.        
  1025.         //
  1026.         internal SplitWritesState(BufferOffsetSize[] buffers)
  1027.         {
  1028.             _UserBuffers = buffers;
  1029.             _LastBufferConsumed = 0;
  1030.             _Index = 0;
  1031.             _RealBuffers = null;
  1032.         }
  1033.         //
  1034.         // Everything was handled
  1035.         //
  1036.         internal bool IsDone {
  1037.             get {
  1038.                 if (_LastBufferConsumed != 0)
  1039.                     return false;
  1040.                
  1041.                 for (int index = _Index; index < _UserBuffers.Length; ++index)
  1042.                     if (_UserBuffers[index].Size != 0)
  1043.                         return false;
  1044.                
  1045.                 return true;
  1046.             }
  1047.         }
  1048.         // Encryption takes CPU and if the input is large (like 10 mb) then a delay may
  1049.         // be 30 sec or so. Hence split the ecnrypt and write operations in smaller chunks
  1050.         // up to c_SplitEncryptedBuffersSize total.
  1051.         // Note that upon return from here EncryptBuffers() may additonally split the input
  1052.         // into chunks each <= chkSecureChannel.MaxDataSize (~16k) yet it will complete them all as a single IO.
  1053.         //
  1054.         // Returns null if done, returns the _buffers reference if everything is handled in one shot (also done)
  1055.         //
  1056.         // Otheriwse returns subsequent BufferOffsetSize[] to encrypt and pass to base IO method
  1057.         //
  1058.         internal BufferOffsetSize[] GetNextBuffers()
  1059.         {
  1060.             int curIndex = _Index;
  1061.             int currentTotalSize = 0;
  1062.             int lastChunkSize = 0;
  1063.            
  1064.             int firstBufferConsumed = _LastBufferConsumed;
  1065.            
  1066.             for (; _Index < _UserBuffers.Length; ++_Index) {
  1067.                 lastChunkSize = _UserBuffers[_Index].Size - _LastBufferConsumed;
  1068.                
  1069.                 currentTotalSize += lastChunkSize;
  1070.                
  1071.                 if (currentTotalSize > c_SplitEncryptedBuffersSize) {
  1072.                     lastChunkSize -= (currentTotalSize - c_SplitEncryptedBuffersSize);
  1073.                     currentTotalSize = c_SplitEncryptedBuffersSize;
  1074.                     break;
  1075.                 }
  1076.                
  1077.                 lastChunkSize = 0;
  1078.                 _LastBufferConsumed = 0;
  1079.             }
  1080.            
  1081.             // Are we done done?
  1082.             if (currentTotalSize == 0)
  1083.                 return null;
  1084.            
  1085.             // Do all buffers fit the limit?
  1086.             if (firstBufferConsumed == 0 && curIndex == 0 && _Index == _UserBuffers.Length)
  1087.                 return _UserBuffers;
  1088.            
  1089.             // We do have something to split and send out
  1090.             int buffersCount = lastChunkSize == 0 ? _Index - curIndex : _Index - curIndex + 1;
  1091.            
  1092.             if (_RealBuffers == null || _RealBuffers.Length != buffersCount)
  1093.                 _RealBuffers = new BufferOffsetSize[buffersCount];
  1094.            
  1095.             int j = 0;
  1096.             for (; curIndex < _Index; ++curIndex) {
  1097.                 _RealBuffers[j++] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + firstBufferConsumed, _UserBuffers[curIndex].Size - firstBufferConsumed, false);
  1098.                 firstBufferConsumed = 0;
  1099.             }
  1100.            
  1101.             if (lastChunkSize != 0) {
  1102.                 _RealBuffers[j] = new BufferOffsetSize(_UserBuffers[curIndex].Buffer, _UserBuffers[curIndex].Offset + _LastBufferConsumed, lastChunkSize, false);
  1103.                 if ((_LastBufferConsumed += lastChunkSize) == _UserBuffers[_Index].Size) {
  1104.                     ++_Index;
  1105.                     _LastBufferConsumed = 0;
  1106.                 }
  1107.             }
  1108.            
  1109.             return _RealBuffers;
  1110.            
  1111.         }
  1112.     }
  1113. }

Developer Fusion