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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="WebHeaderCollection.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.Net.Cache;
  18.     using System.Collections;
  19.     using System.Collections.Specialized;
  20.     using System.Text;
  21.     using System.Runtime.InteropServices;
  22.     using System.Runtime.Serialization;
  23.     using System.Globalization;
  24.     using System.Security.Permissions;
  25.    
  26.     internal enum WebHeaderCollectionType : ushort
  27.     {
  28.         Unknown,
  29.         WebRequest,
  30.         WebResponse,
  31.         HttpWebRequest,
  32.         HttpWebResponse,
  33.         HttpListenerRequest,
  34.         HttpListenerResponse,
  35.         FtpWebRequest,
  36.         FtpWebResponse,
  37.         FileWebRequest,
  38.         FileWebResponse
  39.     }
  40.    
  41.     //
  42.     // HttpHeaders - this is our main HttpHeaders object,
  43.     // which is a simple collection of name-value pairs,
  44.     // along with additional methods that provide HTTP parsing
  45.     // collection to sendable buffer capablities and other enhansments
  46.     // We also provide validation of what headers are allowed to be added.
  47.     //
  48.    
  49.     /// <devdoc>
  50.     /// <para>
  51.     /// Contains protocol headers associated with a
  52.     /// request or response.
  53.     /// </para>
  54.     /// </devdoc>
  55.     [ComVisible(true), Serializable()]
  56.     public class WebHeaderCollection : NameValueCollection, ISerializable
  57.     {
  58.         //
  59.         // Data and Constants
  60.         //
  61.         private const int ApproxAveHeaderLineSize = 30;
  62.         private const int ApproxHighAvgNumHeaders = 16;
  63.         private static readonly HeaderInfoTable HInfo = new HeaderInfoTable();
  64.        
  65.         //
  66.         // Common Headers - used only when receiving a response, and internally. If the user ever requests a header,
  67.         // all the common headers are moved into the hashtable.
  68.         //
  69.         private string[] m_CommonHeaders;
  70.         private int m_NumCommonHeaders;
  71.        
  72.         // Grouped by first character, so lookup is faster. The table s_CommonHeaderHints maps first letters to indexes in this array.
  73.         // After first character, sort by decreasing length. It's ok if two headers have the same first character and length.
  74.         private static readonly string[] s_CommonHeaderNames = new string[] {HttpKnownHeaderNames.AcceptRanges, HttpKnownHeaderNames.ContentLength, HttpKnownHeaderNames.CacheControl, HttpKnownHeaderNames.ContentType, HttpKnownHeaderNames.Date, HttpKnownHeaderNames.Expires, HttpKnownHeaderNames.ETag, HttpKnownHeaderNames.LastModified, HttpKnownHeaderNames.Location, HttpKnownHeaderNames.ProxyAuthenticate,
  75.             // "Accept-Ranges" 13
  76.             // "Content-Length" 14
  77.             // "Cache-Control" 13
  78.             // "Content-Type" 12
  79.             // "Date" 4
  80.             // "Expires" 7
  81.             // "ETag" 4
  82.             // "Last-Modified" 13
  83.             // "Location" 8
  84.             // "Proxy-Authenticate" 18
  85.             // "P3P" 3
  86.             // "Set-Cookie2" 11
  87.             // "Set-Cookie" 10
  88.             // "Server" 6
  89.             // "Via" 3
  90.             // "WWW-Authenticate" 16
  91.             // "X-AspNet-Version" 16
  92.             // "X-Powered-By" 12
  93.         HttpKnownHeaderNames.P3P, HttpKnownHeaderNames.SetCookie2, HttpKnownHeaderNames.SetCookie, HttpKnownHeaderNames.Server, HttpKnownHeaderNames.Via, HttpKnownHeaderNames.WWWAuthenticate, HttpKnownHeaderNames.XAspNetVersion, HttpKnownHeaderNames.XPoweredBy, "["};
  94.         // This sentinel will never match. (This character isn't in the hint table.)
  95.         // Mask off all but the bottom five bits, and look up in this array.
  96.         private static readonly sbyte[] s_CommonHeaderHints = new sbyte[] {-1, 0, -1, 1, 4, 5, -1, -1, -1, -1,
  97.         -1, -1, 7, -1, -1, -1, 9, -1, -1, 11,
  98.         -1, -1, 14, 15, 16, -1, -1, -1, -1, -1,
  99.             // - a b c d e f g
  100.             // h i j k l m n o
  101.             // p q r s t u v w
  102.         -1, -1};
  103.         // x y z [ - - - -
  104.         private const int c_AcceptRanges = 0;
  105.         private const int c_ContentLength = 1;
  106.         private const int c_CacheControl = 2;
  107.         private const int c_ContentType = 3;
  108.         private const int c_Date = 4;
  109.         private const int c_Expires = 5;
  110.         private const int c_ETag = 6;
  111.         private const int c_LastModified = 7;
  112.         private const int c_Location = 8;
  113.         private const int c_ProxyAuthenticate = 9;
  114.         private const int c_P3P = 10;
  115.         private const int c_SetCookie2 = 11;
  116.         private const int c_SetCookie = 12;
  117.         private const int c_Server = 13;
  118.         private const int c_Via = 14;
  119.         private const int c_WwwAuthenticate = 15;
  120.         private const int c_XAspNetVersion = 16;
  121.         private const int c_XPoweredBy = 17;
  122.        
  123.         // Easy fast lookups for common headers. More can be added.
  124.         internal string ContentLength {
  125.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_ContentLength] : Get(s_CommonHeaderNames[c_ContentLength]); }
  126.         }
  127.        
  128.         internal string CacheControl {
  129.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_CacheControl] : Get(s_CommonHeaderNames[c_CacheControl]); }
  130.         }
  131.        
  132.         internal string ContentType {
  133.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_ContentType] : Get(s_CommonHeaderNames[c_ContentType]); }
  134.         }
  135.        
  136.         internal string Date {
  137.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_Date] : Get(s_CommonHeaderNames[c_Date]); }
  138.         }
  139.        
  140.         internal string Expires {
  141.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_Expires] : Get(s_CommonHeaderNames[c_Expires]); }
  142.         }
  143.        
  144.         internal string ETag {
  145.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_ETag] : Get(s_CommonHeaderNames[c_ETag]); }
  146.         }
  147.        
  148.         internal string LastModified {
  149.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_LastModified] : Get(s_CommonHeaderNames[c_LastModified]); }
  150.         }
  151.        
  152.         internal string Location {
  153.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_Location] : Get(s_CommonHeaderNames[c_Location]); }
  154.         }
  155.        
  156.         internal string ProxyAuthenticate {
  157.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_ProxyAuthenticate] : Get(s_CommonHeaderNames[c_ProxyAuthenticate]); }
  158.         }
  159.        
  160.         internal string SetCookie2 {
  161.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_SetCookie2] : Get(s_CommonHeaderNames[c_SetCookie2]); }
  162.         }
  163.        
  164.         internal string SetCookie {
  165.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_SetCookie] : Get(s_CommonHeaderNames[c_SetCookie]); }
  166.         }
  167.        
  168.         internal string Server {
  169.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_Server] : Get(s_CommonHeaderNames[c_Server]); }
  170.         }
  171.        
  172.         internal string Via {
  173.             get { return m_CommonHeaders != null ? m_CommonHeaders[c_Via] : Get(s_CommonHeaderNames[c_Via]); }
  174.         }
  175.        
  176.         private void NormalizeCommonHeaders()
  177.         {
  178.             if (m_CommonHeaders == null)
  179.                 return;
  180.             for (int i = 0; i < m_CommonHeaders.Length; i++)
  181.                 if (m_CommonHeaders[i] != null)
  182.                     InnerCollection.Add(s_CommonHeaderNames[i], m_CommonHeaders[i]);
  183.            
  184.             m_CommonHeaders = null;
  185.             m_NumCommonHeaders = 0;
  186.         }
  187.        
  188.         //
  189.         // To ensure C++ and IL callers can't pollute the underlying collection by calling overridden base members directly, we
  190.         // will use a member collection instead.
  191.         private NameValueCollection m_InnerCollection;
  192.        
  193.         private NameValueCollection InnerCollection {
  194.             get {
  195.                 if (m_InnerCollection == null)
  196.                     m_InnerCollection = new NameValueCollection(ApproxHighAvgNumHeaders, CaseInsensitiveAscii.StaticInstance);
  197.                 return m_InnerCollection;
  198.             }
  199.         }
  200.        
  201.         // this is the object that created the header collection.
  202.         private WebHeaderCollectionType m_Type;
  203.        
  204.        
  205.         // In general, HttpWebResponse headers aren't modified, so these methods don't support common headers.
  206.        
  207.         /// <devdoc>
  208.         /// <para>[To be supplied.]</para>
  209.         /// </devdoc>
  210.         protected void AddWithoutValidate(string headerName, string headerValue)
  211.         {
  212.             headerName = CheckBadChars(headerName, false);
  213.             headerValue = CheckBadChars(headerValue, true);
  214.             GlobalLog.Print("WebHeaderCollection::AddWithoutValidate() calling InnerCollection.Add() key:[" + headerName + "], value:[" + headerValue + "]");
  215.             if (m_Type == WebHeaderCollectionType.HttpListenerResponse) {
  216.                 if (headerValue != null && headerValue.Length > ushort.MaxValue) {
  217.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
  218.                 }
  219.             }
  220.             NormalizeCommonHeaders();
  221.             InvalidateCachedArrays();
  222.             InnerCollection.Add(headerName, headerValue);
  223.         }
  224.        
  225.         internal void SetAddVerified(string name, string value)
  226.         {
  227.             if (HInfo[name].AllowMultiValues) {
  228.                 GlobalLog.Print("WebHeaderCollection::SetAddVerified() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
  229.                 NormalizeCommonHeaders();
  230.                 InvalidateCachedArrays();
  231.                 InnerCollection.Add(name, value);
  232.             }
  233.             else {
  234.                 GlobalLog.Print("WebHeaderCollection::SetAddVerified() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
  235.                 NormalizeCommonHeaders();
  236.                 InvalidateCachedArrays();
  237.                 InnerCollection.Set(name, value);
  238.             }
  239.         }
  240.        
  241.         // Below three methods are for fast headers manipulation, bypassing all the checks
  242.         internal void AddInternal(string name, string value)
  243.         {
  244.             GlobalLog.Print("WebHeaderCollection::AddInternal() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
  245.             NormalizeCommonHeaders();
  246.             InvalidateCachedArrays();
  247.             InnerCollection.Add(name, value);
  248.         }
  249.        
  250.         internal void ChangeInternal(string name, string value)
  251.         {
  252.             GlobalLog.Print("WebHeaderCollection::ChangeInternal() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
  253.             NormalizeCommonHeaders();
  254.             InvalidateCachedArrays();
  255.             InnerCollection.Set(name, value);
  256.         }
  257.        
  258.        
  259.         internal void RemoveInternal(string name)
  260.         {
  261.             GlobalLog.Print("WebHeaderCollection::RemoveInternal() calling InnerCollection.Remove() key:[" + name + "]");
  262.             NormalizeCommonHeaders();
  263.             if (m_InnerCollection != null) {
  264.                 InvalidateCachedArrays();
  265.                 m_InnerCollection.Remove(name);
  266.             }
  267.         }
  268.        
  269.         internal void CheckUpdate(string name, string value)
  270.         {
  271.             value = CheckBadChars(value, true);
  272.             ChangeInternal(name, value);
  273.         }
  274.        
  275.         // This even faster one can be used to add headers when it's known not to be a common header or that common headers aren't active.
  276.         private void AddInternalNotCommon(string name, string value)
  277.         {
  278.             GlobalLog.Print("WebHeaderCollection::AddInternalNotCommon() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
  279.             InvalidateCachedArrays();
  280.             InnerCollection.Add(name, value);
  281.         }
  282.        
  283.        
  284.         private static readonly char[] HttpTrimCharacters = new char[] {(char)9, (char)10, (char)11, (char)12, (char)13, (char)32};
  285.        
  286.         //
  287.         // CheckBadChars - throws on invalid chars to be not found in header name/value
  288.         //
  289.         static internal string CheckBadChars(string name, bool isHeaderValue)
  290.         {
  291.            
  292.             if (name == null || name.Length == 0) {
  293.                 // emtpy name is invlaid
  294.                 if (!isHeaderValue) {
  295.                     throw name == null ? new ArgumentNullException("name") : new ArgumentException(SR.GetString(SR.net_emptystringcall, "name"), "name");
  296.                 }
  297.                 //empty value is OK
  298.                 return string.Empty;
  299.             }
  300.            
  301.             if (isHeaderValue) {
  302.                 // VALUE check
  303.                 //Trim spaces from both ends
  304.                 name = name.Trim(HttpTrimCharacters);
  305.                
  306.                 //First, check for correctly formed multi-line value
  307.                 //Second, check for absenece of CTL characters
  308.                 int crlf = 0;
  309.                 for (int i = 0; i < name.Length; ++i) {
  310.                     char c = (char)(255 & (uint)name[i]);
  311.                     switch (crlf) {
  312.                         case 0:
  313.                             if (c == '\r') {
  314.                                 crlf = 1;
  315.                             }
  316.                             else if (c == '\n') {
  317.                                 crlf = 2;
  318.                             }
  319.                             else if (c == 127 || (c < ' ' && c != '\t')) {
  320.                                 throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidControlChars), "value");
  321.                             }
  322.                             break;
  323.                         case 1:
  324.                            
  325.                             if (c == '\n') {
  326.                                 crlf = 2;
  327.                                 break;
  328.                             }
  329.                             throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value");
  330.                             break;
  331.                         case 2:
  332.                            
  333.                             if (c == ' ' || c == '\t') {
  334.                                 crlf = 0;
  335.                                 break;
  336.                             }
  337.                             throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value");
  338.                             break;
  339.                     }
  340.                 }
  341.                 if (crlf != 0) {
  342.                     throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value");
  343.                 }
  344.             }
  345.             else {
  346.                 // NAME check
  347.                 //First, check for absence of separators and spaces
  348.                 if (name.IndexOfAny(ValidationHelper.InvalidParamChars) != -1) {
  349.                     throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidHeaderChars), "name");
  350.                 }
  351.                
  352.                 //Second, check for non CTL ASCII-7 characters (32-126)
  353.                 if (ContainsNonAsciiChars(name)) {
  354.                     throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidNonAsciiChars), "name");
  355.                 }
  356.             }
  357.             return name;
  358.         }
  359.        
  360.         static internal bool IsValidToken(string token)
  361.         {
  362.             return (token.Length > 0) && (token.IndexOfAny(ValidationHelper.InvalidParamChars) == -1) && !ContainsNonAsciiChars(token);
  363.         }
  364.        
  365.         static internal bool ContainsNonAsciiChars(string token)
  366.         {
  367.             for (int i = 0; i < token.Length; ++i) {
  368.                 if ((token[i] < 32) || (token[i] > 126)) {
  369.                     return true;
  370.                 }
  371.             }
  372.             return false;
  373.         }
  374.        
  375.         //
  376.         // ThrowOnRestrictedHeader - generates an error if the user,
  377.         // passed in a reserved string as the header name
  378.         //
  379.         internal void ThrowOnRestrictedHeader(string headerName)
  380.         {
  381.             if (m_Type == WebHeaderCollectionType.HttpWebRequest) {
  382.                 if (HInfo[headerName].IsRequestRestricted) {
  383.                     throw new ArgumentException(!Equals(headerName, HttpKnownHeaderNames.Host) ? SR.GetString(SR.net_headerrestrict) : SR.GetString(SR.net_headerrestrict_resp, HttpKnownHeaderNames.Host), "name");
  384.                 }
  385.             }
  386.             else if (m_Type == WebHeaderCollectionType.HttpListenerResponse) {
  387.                 if (HInfo[headerName].IsResponseRestricted) {
  388.                     throw new ArgumentException(SR.GetString(SR.net_headerrestrict_resp, headerName), "name");
  389.                 }
  390.             }
  391.         }
  392.        
  393.         //
  394.         // Our Public METHOD set, most are inherited from NameValueCollection,
  395.         // not all methods from NameValueCollection are listed, even though usable -
  396.         //
  397.         // this includes
  398.         // Add(name, value)
  399.         // Add(header)
  400.         // this[name] {set, get}
  401.         // Remove(name), returns bool
  402.         // Remove(name), returns void
  403.         // Set(name, value)
  404.         // ToString()
  405.         //
  406.         // SplitValue(name, value)
  407.         // ToByteArray()
  408.         // ParseHeaders(char [], ...)
  409.         // ParseHeaders(byte [], ...)
  410.         //
  411.        
  412.         // Add more headers; if "name" already exists it will
  413.         // add concatenated value
  414.        
  415.        
  416.         // Add -
  417.         // Routine Description:
  418.         // Adds headers with validation to see if they are "proper" headers.
  419.         // Will cause header to be concat to existing if already found.
  420.         // If the header is a special header, listed in RestrictedHeaders object,
  421.         // then this call will cause an exception indication as such.
  422.         // Arguments:
  423.         // name - header-name to add
  424.         // value - header-value to add, a header is already there, will concat this value
  425.         // Return Value:
  426.         // None
  427.        
  428.         /// <devdoc>
  429.         /// <para>
  430.         /// Adds a new header with the indicated name and value.
  431.         /// </para>
  432.         /// </devdoc>
  433.         public override void Add(string name, string value)
  434.         {
  435.             name = CheckBadChars(name, false);
  436.             ThrowOnRestrictedHeader(name);
  437.             value = CheckBadChars(value, true);
  438.             GlobalLog.Print("WebHeaderCollection::Add() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
  439.             if (m_Type == WebHeaderCollectionType.HttpListenerResponse) {
  440.                 if (value != null && value.Length > ushort.MaxValue) {
  441.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
  442.                 }
  443.             }
  444.             NormalizeCommonHeaders();
  445.             InvalidateCachedArrays();
  446.             InnerCollection.Add(name, value);
  447.         }
  448.        
  449.        
  450.         // Add -
  451.         // Routine Description:
  452.         // Adds headers with validation to see if they are "proper" headers.
  453.         // Assumes a combined a "Name: Value" string, and parses the two parts out.
  454.         // Will cause header to be concat to existing if already found.
  455.         // If the header is a speical header, listed in RestrictedHeaders object,
  456.         // then this call will cause an exception indication as such.
  457.         // Arguments:
  458.         // header - header name: value pair
  459.         // Return Value:
  460.         // None
  461.        
  462.         /// <devdoc>
  463.         /// <para>
  464.         /// Adds the indicated header.
  465.         /// </para>
  466.         /// </devdoc>
  467.         public void Add(string header)
  468.         {
  469.             if (ValidationHelper.IsBlankString(header)) {
  470.                 throw new ArgumentNullException("header");
  471.             }
  472.             int colpos = header.IndexOf(':');
  473.             // check for badly formed header passed in
  474.             if (colpos < 0) {
  475.                 throw new ArgumentException(SR.GetString(SR.net_WebHeaderMissingColon), "header");
  476.             }
  477.             string name = header.Substring(0, colpos);
  478.             string value = header.Substring(colpos + 1);
  479.             name = CheckBadChars(name, false);
  480.             ThrowOnRestrictedHeader(name);
  481.             value = CheckBadChars(value, true);
  482.             GlobalLog.Print("WebHeaderCollection::Add(" + header + ") calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
  483.             if (m_Type == WebHeaderCollectionType.HttpListenerResponse) {
  484.                 if (value != null && value.Length > ushort.MaxValue) {
  485.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
  486.                 }
  487.             }
  488.             NormalizeCommonHeaders();
  489.             InvalidateCachedArrays();
  490.             InnerCollection.Add(name, value);
  491.         }
  492.        
  493.         // Set -
  494.         // Routine Description:
  495.         // Sets headers with validation to see if they are "proper" headers.
  496.         // If the header is a special header, listed in RestrictedHeaders object,
  497.         // then this call will cause an exception indication as such.
  498.         // Arguments:
  499.         // name - header-name to set
  500.         // value - header-value to set
  501.         // Return Value:
  502.         // None
  503.        
  504.         /// <devdoc>
  505.         /// <para>
  506.         /// Sets the specified header to the specified value.
  507.         /// </para>
  508.         /// </devdoc>
  509.         public override void Set(string name, string value)
  510.         {
  511.             if (ValidationHelper.IsBlankString(name)) {
  512.                 throw new ArgumentNullException("name");
  513.             }
  514.             name = CheckBadChars(name, false);
  515.             ThrowOnRestrictedHeader(name);
  516.             value = CheckBadChars(value, true);
  517.             GlobalLog.Print("WebHeaderCollection::Set() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
  518.             if (m_Type == WebHeaderCollectionType.HttpListenerResponse) {
  519.                 if (value != null && value.Length > ushort.MaxValue) {
  520.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
  521.                 }
  522.             }
  523.             NormalizeCommonHeaders();
  524.             InvalidateCachedArrays();
  525.             InnerCollection.Set(name, value);
  526.         }
  527.        
  528.        
  529.         internal void SetInternal(string name, string value)
  530.         {
  531.             if (ValidationHelper.IsBlankString(name)) {
  532.                 throw new ArgumentNullException("name");
  533.             }
  534.             name = CheckBadChars(name, false);
  535.             value = CheckBadChars(value, true);
  536.             GlobalLog.Print("WebHeaderCollection::Set() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
  537.             if (m_Type == WebHeaderCollectionType.HttpListenerResponse) {
  538.                 if (value != null && value.Length > ushort.MaxValue) {
  539.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
  540.                 }
  541.             }
  542.             NormalizeCommonHeaders();
  543.             InvalidateCachedArrays();
  544.             InnerCollection.Set(name, value);
  545.         }
  546.        
  547.        
  548.         // Remove -
  549.         // Routine Description:
  550.         // Removes give header with validation to see if they are "proper" headers.
  551.         // If the header is a speical header, listed in RestrictedHeaders object,
  552.         // then this call will cause an exception indication as such.
  553.         // Arguments:
  554.         // name - header-name to remove
  555.         // Return Value:
  556.         // None
  557.        
  558.         /// <devdoc>
  559.         /// <para>Removes the specified header.</para>
  560.         /// </devdoc>
  561.         public override void Remove(string name)
  562.         {
  563.             if (ValidationHelper.IsBlankString(name)) {
  564.                 throw new ArgumentNullException("name");
  565.             }
  566.             ThrowOnRestrictedHeader(name);
  567.             name = CheckBadChars(name, false);
  568.             GlobalLog.Print("WebHeaderCollection::Remove() calling InnerCollection.Remove() key:[" + name + "]");
  569.             NormalizeCommonHeaders();
  570.             if (m_InnerCollection != null) {
  571.                 InvalidateCachedArrays();
  572.                 m_InnerCollection.Remove(name);
  573.             }
  574.         }
  575.        
  576.        
  577.         // GetValues
  578.         // Routine Description:
  579.         // This method takes a header name and returns a string array representing
  580.         // the individual values for that headers. For example, if the headers
  581.         // contained the line Accept: text/plain, text/html then
  582.         // GetValues("Accept") would return an array of two strings: "text/plain"
  583.         // and "text/html".
  584.         // Arguments:
  585.         // header - Name of the header.
  586.         // Return Value:
  587.         // string[] - array of parsed string objects
  588.        
  589.         /// <devdoc>
  590.         /// <para>
  591.         /// Gets an array of header values stored in a
  592.         /// header.
  593.         /// </para>
  594.         /// </devdoc>
  595.         public override string[] GetValues(string header)
  596.         {
  597.             NormalizeCommonHeaders();
  598.            
  599.             // First get the information about the header and the values for
  600.             // the header.
  601.             HeaderInfo Info = HInfo[header];
  602.             string[] Values = InnerCollection.GetValues(header);
  603.             // If we have no information about the header or it doesn't allow
  604.             // multiple values, just return the values.
  605.             if (Info == null || Values == null || !Info.AllowMultiValues) {
  606.                 return Values;
  607.             }
  608.             // Here we have a multi value header. We need to go through
  609.             // each entry in the multi values array, and if an entry itself
  610.             // has multiple values we'll need to combine those in.
  611.             //
  612.             // We do some optimazation here, where we try not to copy the
  613.             // values unless there really is one that have multiple values.
  614.             string[] TempValues;
  615.             ArrayList ValueList = null;
  616.             int i;
  617.             for (i = 0; i < Values.Length; i++) {
  618.                 // Parse this value header.
  619.                 TempValues = Info.Parser(Values[i]);
  620.                 // If we don't have an array list yet, see if this
  621.                 // value has multiple values.
  622.                 if (ValueList == null) {
  623.                     // See if it has multiple values.
  624.                     if (TempValues.Length > 1) {
  625.                         // It does, so we need to create an array list that
  626.                         // represents the Values, then trim out this one and
  627.                         // the ones after it that haven't been parsed yet.
  628.                         ValueList = new ArrayList(Values);
  629.                         ValueList.RemoveRange(i, Values.Length - i);
  630.                         ValueList.AddRange(TempValues);
  631.                     }
  632.                 }
  633.                 else {
  634.                     // We already have an ArrayList, so just add the values.
  635.                     ValueList.AddRange(TempValues);
  636.                 }
  637.             }
  638.             // See if we have an ArrayList. If we don't, just return the values.
  639.             // Otherwise convert the ArrayList to a string array and return that.
  640.             if (ValueList != null) {
  641.                 string[] ReturnArray = new string[ValueList.Count];
  642.                 ValueList.CopyTo(ReturnArray);
  643.                 return ReturnArray;
  644.             }
  645.             return Values;
  646.         }
  647.        
  648.        
  649.         // ToString() -
  650.         // Routine Description:
  651.         // Generates a string representation of the headers, that is ready to be sent except for it being in string format:
  652.         // the format looks like:
  653.         //
  654.         // Header-Name: Header-Value\r\n
  655.         // Header-Name2: Header-Value2\r\n
  656.         // ...
  657.         // Header-NameN: Header-ValueN\r\n
  658.         // \r\n
  659.         //
  660.         // Uses the string builder class to Append the elements together.
  661.         // Arguments:
  662.         // None.
  663.         // Return Value:
  664.         // string
  665.        
  666.         /// <internalonly/>
  667.         /// <devdoc>
  668.         /// <para>
  669.         /// Obsolete.
  670.         /// </para>
  671.         /// </devdoc>
  672.         public override string ToString()
  673.         {
  674.             string result = GetAsString(this, false, false);
  675.             GlobalLog.Print("WebHeaderCollection::ToString: \r\n" + result);
  676.             return result;
  677.         }
  678.        
  679.         internal string ToString(bool forTrace)
  680.         {
  681.             return GetAsString(this, false, true);
  682.         }
  683.        
  684.        
  685.         //
  686.         // if winInetCompat = true then it will not insert spaces after ':'
  687.         // and it will output "~U" header first
  688.         //
  689.         static internal string GetAsString(NameValueCollection cc, bool winInetCompat, bool forTrace)
  690.         {
  691.             if (winInetCompat) {
  692.                 throw new InvalidOperationException();
  693.             }
  694.            
  695.             if (cc == null || cc.Count == 0) {
  696.                 return "\r\n";
  697.             }
  698.             StringBuilder sb = new StringBuilder(ApproxAveHeaderLineSize * cc.Count);
  699.             string statusLine;
  700.             statusLine = cc[string.Empty];
  701.             if (statusLine != null) {
  702.                 sb.Append(statusLine).Append("\r\n");
  703.             }
  704.             for (int i = 0; i < cc.Count; i++) {
  705.                 string key = cc.GetKey(i) as string;
  706.                 string val = cc.Get(i) as string;
  707.                 /*
  708.                 if (forTrace)
  709.                 {
  710.                     // Put a condition here that if we are using basic auth,
  711.                     // we shouldn't put the authorization header. Otherwise
  712.                     // the password will get saved in the trace.
  713.                     if (using basic)
  714.                         continue;
  715.                 }
  716.                 */               
  717. if (ValidationHelper.IsBlankString(key)) {
  718.                     continue;
  719.                 }
  720.                 sb.Append(key);
  721.                 if (winInetCompat) {
  722.                     sb.Append(':');
  723.                 }
  724.                 else {
  725.                     sb.Append(": ");
  726.                 }
  727.                 sb.Append(val).Append("\r\n");
  728.             }
  729.             if (!forTrace)
  730.                 sb.Append("\r\n");
  731.             return sb.ToString();
  732.         }
  733.        
  734.        
  735.         // ToByteArray() -
  736.         // Routine Description:
  737.         // Generates a byte array representation of the headers, that is ready to be sent.
  738.         // So it Serializes our headers into a byte array suitable for sending over the net.
  739.         //
  740.         // the format looks like:
  741.         //
  742.         // Header-Name1: Header-Value1\r\n
  743.         // Header-Name2: Header-Value2\r\n
  744.         // ...
  745.         // Header-NameN: Header-ValueN\r\n
  746.         // \r\n
  747.         //
  748.         // Uses the ToString() method to generate, and then performs conversion.
  749.         //
  750.         // Performance Note: Why are we not doing a single copy/covert run?
  751.         // As the code before used to know the size of the output!
  752.         // Because according to Demitry, its cheaper to copy the headers twice,
  753.         // then it is to call the UNICODE to ANSI conversion code many times.
  754.         // Arguments:
  755.         // None.
  756.         // Return Value:
  757.         // byte [] - array of bytes values
  758.        
  759.         /// <internalonly/>
  760.         /// <devdoc>
  761.         /// <para>
  762.         /// Obsolete.
  763.         /// </para>
  764.         /// </devdoc>
  765.         public byte[] ToByteArray()
  766.         {
  767.             // Make sure the buffer is big enough.
  768.             string tempStr = ToString();
  769.             //
  770.             // Use the string of headers, convert to Char Array,
  771.             // then convert to Bytes,
  772.             // serializing finally into the buffer, along the way.
  773.             //
  774.             byte[] buffer = HeaderEncoding.GetBytes(tempStr);
  775.             return buffer;
  776.         }
  777.        
  778.         /// <devdoc>
  779.         /// <para>Tests if access to the HTTP header with the provided name is accessible for setting.</para>
  780.         /// </devdoc>
  781.         public static bool IsRestricted(string headerName)
  782.         {
  783.             return IsRestricted(headerName, false);
  784.         }
  785.        
  786.         public static bool IsRestricted(string headerName, bool response)
  787.         {
  788.             return response ? HInfo[CheckBadChars(headerName, false)].IsResponseRestricted : HInfo[CheckBadChars(headerName, false)].IsRequestRestricted;
  789.         }
  790.        
  791.        
  792.         /// <devdoc>
  793.         /// <para>
  794.         /// Initializes a new instance of the <see cref='System.Net.WebHeaderCollection'/>
  795.         /// class.
  796.         /// </para>
  797.         /// </devdoc>
  798.         public WebHeaderCollection() : base(DBNull.Value)
  799.         {
  800.         }
  801.        
  802.         internal WebHeaderCollection(WebHeaderCollectionType type) : base(DBNull.Value)
  803.         {
  804.             m_Type = type;
  805.             if (type == WebHeaderCollectionType.HttpWebResponse)
  806.                 m_CommonHeaders = new string[s_CommonHeaderNames.Length - 1];
  807.             // Minus one for the sentinel.
  808.         }
  809.        
  810.         //This is for Cache
  811.         internal WebHeaderCollection(NameValueCollection cc) : base(DBNull.Value)
  812.         {
  813.             m_InnerCollection = new NameValueCollection(cc.Count + 2, CaseInsensitiveAscii.StaticInstance);
  814.             int len = cc.Count;
  815.             for (int i = 0; i < len; ++i) {
  816.                 string key = cc.GetKey(i);
  817.                 string[] values = cc.GetValues(i);
  818.                 if (values != null) {
  819.                     for (int j = 0; j < values.Length; j++) {
  820.                         InnerCollection.Add(key, values[j]);
  821.                     }
  822.                 }
  823.                 else {
  824.                     InnerCollection.Add(key, null);
  825.                 }
  826.             }
  827.         }
  828.        
  829.         //
  830.         // ISerializable constructor
  831.         //
  832.         /// <devdoc>
  833.         /// <para>[To be supplied.]</para>
  834.         /// </devdoc>
  835.         protected WebHeaderCollection(SerializationInfo serializationInfo, StreamingContext streamingContext) : base(DBNull.Value)
  836.         {
  837.             int count = serializationInfo.GetInt32("Count");
  838.             m_InnerCollection = new NameValueCollection(count + 2, CaseInsensitiveAscii.StaticInstance);
  839.             for (int i = 0; i < count; i++) {
  840.                 string headerName = serializationInfo.GetString(i.ToString(NumberFormatInfo.InvariantInfo));
  841.                 string headerValue = serializationInfo.GetString((i + count).ToString(NumberFormatInfo.InvariantInfo));
  842.                 GlobalLog.Print("WebHeaderCollection::.ctor(ISerializable) calling InnerCollection.Add() key:[" + headerName + "], value:[" + headerValue + "]");
  843.                 InnerCollection.Add(headerName, headerValue);
  844.             }
  845.         }
  846.        
  847.         public override void OnDeserialization(object sender)
  848.         {
  849.         }
  850.        
  851.         //
  852.         // ISerializable method
  853.         //
  854.         /// <internalonly/>
  855.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  856.         public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
  857.         {
  858.             //
  859.             // for now disregard streamingContext.
  860.             //
  861.             NormalizeCommonHeaders();
  862.             serializationInfo.AddValue("Count", Count);
  863.             for (int i = 0; i < Count; i++) {
  864.                 serializationInfo.AddValue(i.ToString(NumberFormatInfo.InvariantInfo), GetKey(i));
  865.                 serializationInfo.AddValue((i + Count).ToString(NumberFormatInfo.InvariantInfo), Get(i));
  866.             }
  867.         }
  868.        
  869.        
  870.         static internal class HeaderEncoding
  871.         {
  872.             unsafe static internal string GetString(byte[] bytes, int byteIndex, int byteCount)
  873.             {
  874.                 fixed (byte* pBytes = bytes)
  875.                     return GetString(pBytes + byteIndex, byteCount);
  876.             }
  877.            
  878.             unsafe static internal string GetString(byte* pBytes, int byteCount)
  879.             {
  880.                 if (byteCount < 1)
  881.                     return "";
  882.                
  883.                 string s = new string('\0', byteCount);
  884.                
  885.                 fixed (char* pStr = s) {
  886.                     char* pString = pStr;
  887.                     while (byteCount >= 8) {
  888.                         pString[0] = (char)pBytes[0];
  889.                         pString[1] = (char)pBytes[1];
  890.                         pString[2] = (char)pBytes[2];
  891.                         pString[3] = (char)pBytes[3];
  892.                         pString[4] = (char)pBytes[4];
  893.                         pString[5] = (char)pBytes[5];
  894.                         pString[6] = (char)pBytes[6];
  895.                         pString[7] = (char)pBytes[7];
  896.                         pString += 8;
  897.                         pBytes += 8;
  898.                         byteCount -= 8;
  899.                     }
  900.                     for (int i = 0; i < byteCount; i++) {
  901.                         pString[i] = (char)pBytes[i];
  902.                     }
  903.                 }
  904.                
  905.                 return s;
  906.             }
  907.            
  908.             static internal int GetByteCount(string myString)
  909.             {
  910.                 return myString.Length;
  911.             }
  912.             unsafe static internal void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex)
  913.             {
  914.                 if (myString.Length == 0) {
  915.                     return;
  916.                 }
  917.                 fixed (byte* bufferPointer = bytes) {
  918.                     byte* newBufferPointer = bufferPointer + byteIndex;
  919.                     int finalIndex = charIndex + charCount;
  920.                     while (charIndex < finalIndex) {
  921.                         *newBufferPointer++ = (byte)myString[charIndex++];
  922.                     }
  923.                 }
  924.             }
  925.             unsafe static internal byte[] GetBytes(string myString)
  926.             {
  927.                 byte[] bytes = new byte[myString.Length];
  928.                 if (myString.Length != 0) {
  929.                     GetBytes(myString, 0, myString.Length, bytes, 0);
  930.                 }
  931.                 return bytes;
  932.             }
  933.         }
  934.        
  935.        
  936.         // ParseHeaders -
  937.         // Routine Description:
  938.         //
  939.         // This code is optimized for the case in which all the headers fit in the buffer.
  940.         // we support multiple re-entrance, but we won't save intermediate
  941.         // state, we will just roll back all the parsing done for the current header if we can't
  942.         // parse a whole one (including multiline) or decide something else ("invalid data" or "done parsing").
  943.         //
  944.         // we're going to cycle through the loop until we
  945.         //
  946.         // 1) find an HTTP violation (in this case we return DataParseStatus.Invalid)
  947.         // 2) we need more data (in this case we return DataParseStatus.NeedMoreData)
  948.         // 3) we found the end of the headers and the beginning of the entity body (in this case we return DataParseStatus.Done)
  949.         //
  950.         //
  951.         // Arguments:
  952.         //
  953.         // buffer - buffer containing the data to be parsed
  954.         // size - size of the buffer
  955.         // unparsed - offset of data yet to be parsed
  956.         //
  957.         // Return Value:
  958.         //
  959.         // DataParseStatus - status of parsing
  960.         //
  961.         // Revision:
  962.         //
  963.         // 02/13/2001 rewrote the method from scratch.
  964.         //
  965.         // BreakPoint:
  966.         //
  967.         // b system.dll!System.Net.WebHeaderCollection::ParseHeaders
  968.         unsafe internal DataParseStatus ParseHeaders(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength, ref WebParseError parseError)
  969.         {
  970.            
  971.             fixed (byte* byteBuffer = buffer) {
  972.                
  973.                 char ch;
  974.                
  975.                 // quick check in the boundaries (as we use unsafe pointer)
  976.                 if (buffer.Length < size) {
  977.                     return DataParseStatus.NeedMoreData;
  978.                 }
  979.                
  980.                 int headerNameStartOffset = -1;
  981.                 int headerNameEndOffset = -1;
  982.                 int headerValueStartOffset = -1;
  983.                 int headerValueEndOffset = -1;
  984.                 int numberOfLf = -1;
  985.                 int index = unparsed;
  986.                 bool spaceAfterLf;
  987.                 string headerMultiLineValue;
  988.                 string headerName;
  989.                 string headerValue;
  990.                
  991.                 // we need this because this method is entered multiple times.
  992.                 int localTotalResponseHeadersLength = totalResponseHeadersLength;
  993.                
  994.                 WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic;
  995.                 DataParseStatus parseStatus = DataParseStatus.Invalid;
  996.                
  997.                 //
  998.                 // according to RFC216 a header can have the following syntax:
  999.                 //
  1000.                 // message-header = field-name ":" [ field-value ]
  1001.                 // field-name = token
  1002.                 // field-value = *( field-content | LWS )
  1003.                 // field-content = <the OCTETs making up the field-value and consisting of either *TEXT or combinations of token, separators, and quoted-string>
  1004.                 // TEXT = <any OCTET except CTLs, but including LWS>
  1005.                 // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
  1006.                 // SP = <US-ASCII SP, space (32)>
  1007.                 // HT = <US-ASCII HT, horizontal-tab (9)>
  1008.                 // CR = <US-ASCII CR, carriage return (13)>
  1009.                 // LF = <US-ASCII LF, linefeed (10)>
  1010.                 // LWS = [CR LF] 1*( SP | HT )
  1011.                 // CHAR = <any US-ASCII character (octets 0 - 127)>
  1012.                 // token = 1*<any CHAR except CTLs or separators>
  1013.                 // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
  1014.                 // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
  1015.                 // qdtext = <any TEXT except <">>
  1016.                 // quoted-pair = "\" CHAR
  1017.                 //
  1018.                
  1019.                 //
  1020.                 // At each iteration of the following loop we expect to parse a single HTTP header entirely.
  1021.                 //
  1022.                 for (;;) {
  1023.                     //
  1024.                     // trim leading whitespaces (LWS) just for extra robustness, in fact if there are leading white spaces then:
  1025.                     // 1) it could be that after the status line we might have spaces. handle this.
  1026.                     // 2) this should have been detected to be a multiline header so there'll be no spaces and we'll spend some time here.
  1027.                     //
  1028.                     headerName = string.Empty;
  1029.                     headerValue = string.Empty;
  1030.                     spaceAfterLf = false;
  1031.                     headerMultiLineValue = null;
  1032.                    
  1033.                     if (Count == 0) {
  1034.                         //
  1035.                         // so, restrict this extra trimming only on the first header line
  1036.                         //
  1037.                         while (index < size) {
  1038.                             ch = (char)byteBuffer[index];
  1039.                             if (ch == ' ' || ch == '\t') {
  1040.                                 ++index;
  1041.                                 if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1042.                                     parseStatus = DataParseStatus.DataTooBig;
  1043.                                     goto quit;
  1044.                                 }
  1045.                             }
  1046.                             else {
  1047.                                 break;
  1048.                             }
  1049.                         }
  1050.                        
  1051.                         if (index == size) {
  1052.                             //
  1053.                             // we reached the end of the buffer. ask for more data.
  1054.                             //
  1055.                             parseStatus = DataParseStatus.NeedMoreData;
  1056.                             goto quit;
  1057.                         }
  1058.                     }
  1059.                    
  1060.                     //
  1061.                     // what we have here is the beginning of a new header
  1062.                     //
  1063.                     headerNameStartOffset = index;
  1064.                    
  1065.                     while (index < size) {
  1066.                         ch = (char)byteBuffer[index];
  1067.                         if (ch != ':' && ch != '\n') {
  1068.                             if (ch > ' ') {
  1069.                                 //
  1070.                                 // if there's an illegal character we should return DataParseStatus.Invalid
  1071.                                 // instead we choose to be flexible, try to trim it, but include it in the string
  1072.                                 //
  1073.                                 headerNameEndOffset = index;
  1074.                             }
  1075.                             ++index;
  1076.                             if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1077.                                 parseStatus = DataParseStatus.DataTooBig;
  1078.                                 goto quit;
  1079.                             }
  1080.                         }
  1081.                         else {
  1082.                             if (ch == ':') {
  1083.                                 ++index;
  1084.                                 if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1085.                                     parseStatus = DataParseStatus.DataTooBig;
  1086.                                     goto quit;
  1087.                                 }
  1088.                             }
  1089.                             break;
  1090.                         }
  1091.                     }
  1092.                     if (index == size) {
  1093.                         //
  1094.                         // we reached the end of the buffer. ask for more data.
  1095.                         //
  1096.                         parseStatus = DataParseStatus.NeedMoreData;
  1097.                         goto quit;
  1098.                     }
  1099.                     startOfValue:
  1100.                    
  1101.                     //
  1102.                     // skip all [' ','\t','\r','\n'] characters until HeaderValue starts
  1103.                     // if we didn't find any headers yet, we set numberOfLf to 1
  1104.                     // so that we take the '\n' from the status line into account
  1105.                     //
  1106.                    
  1107.                     numberOfLf = (Count == 0 && headerNameEndOffset < 0) ? 1 : 0;
  1108.                     while (index < size && numberOfLf < 2) {
  1109.                         ch = (char)byteBuffer[index];
  1110.                         if (ch <= ' ') {
  1111.                             if (ch == '\n') {
  1112.                                 numberOfLf++;
  1113.                                 // In this case, need to check for a space.
  1114.                                 if (numberOfLf == 1) {
  1115.                                     if (index + 1 == size) {
  1116.                                         //
  1117.                                         // we reached the end of the buffer. ask for more data.
  1118.                                         // need to be able to peek after the \n and see if there's some space.
  1119.                                         //
  1120.                                         parseStatus = DataParseStatus.NeedMoreData;
  1121.                                         goto quit;
  1122.                                     }
  1123.                                     spaceAfterLf = (char)byteBuffer[index + 1] == ' ' || (char)byteBuffer[index + 1] == '\t';
  1124.                                 }
  1125.                             }
  1126.                             ++index;
  1127.                             if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1128.                                 parseStatus = DataParseStatus.DataTooBig;
  1129.                                 goto quit;
  1130.                             }
  1131.                         }
  1132.                         else {
  1133.                             break;
  1134.                         }
  1135.                     }
  1136.                     if (numberOfLf == 2 || (numberOfLf == 1 && !spaceAfterLf)) {
  1137.                         //
  1138.                         // if we've counted two '\n' we got at the end of the headers even if we're past the end of the buffer
  1139.                         // if we've counted one '\n' and the first character after that was a ' ' or a '\t'
  1140.                         // no matter if we found a ':' or not, treat this as an empty header name.
  1141.                         //
  1142.                         goto addHeader;
  1143.                     }
  1144.                     if (index == size) {
  1145.                         //
  1146.                         // we reached the end of the buffer. ask for more data.
  1147.                         //
  1148.                         parseStatus = DataParseStatus.NeedMoreData;
  1149.                         goto quit;
  1150.                     }
  1151.                    
  1152.                     headerValueStartOffset = index;
  1153.                    
  1154.                     while (index < size) {
  1155.                         ch = (char)byteBuffer[index];
  1156.                         if (ch != '\n') {
  1157.                             if (ch > ' ') {
  1158.                                 headerValueEndOffset = index;
  1159.                             }
  1160.                             ++index;
  1161.                             if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1162.                                 parseStatus = DataParseStatus.DataTooBig;
  1163.                                 goto quit;
  1164.                             }
  1165.                         }
  1166.                         else {
  1167.                             break;
  1168.                         }
  1169.                     }
  1170.                     if (index == size) {
  1171.                         //
  1172.                         // we reached the end of the buffer. ask for more data.
  1173.                         //
  1174.                         parseStatus = DataParseStatus.NeedMoreData;
  1175.                         goto quit;
  1176.                     }
  1177.                    
  1178.                     //
  1179.                     // at this point we found either a '\n' or the end of the headers
  1180.                     // hence we are at the end of the Header Line. 4 options:
  1181.                     // 1) need more data
  1182.                     // 2) if we find two '\n' => end of headers
  1183.                     // 3) if we find one '\n' and a ' ' or a '\t' => multiline header
  1184.                     // 4) if we find one '\n' and a valid char => next header
  1185.                     //
  1186.                     numberOfLf = 0;
  1187.                     while (index < size && numberOfLf < 2) {
  1188.                         ch = (char)byteBuffer[index];
  1189.                         if (ch == '\r' || ch == '\n') {
  1190.                             if (ch == '\n') {
  1191.                                 numberOfLf++;
  1192.                             }
  1193.                             ++index;
  1194.                             if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1195.                                 parseStatus = DataParseStatus.DataTooBig;
  1196.                                 goto quit;
  1197.                             }
  1198.                         }
  1199.                         else {
  1200.                             break;
  1201.                         }
  1202.                     }
  1203.                     if (index == size && numberOfLf < 2) {
  1204.                         //
  1205.                         // we reached the end of the buffer but not of the headers. ask for more data.
  1206.                         //
  1207.                         parseStatus = DataParseStatus.NeedMoreData;
  1208.                         goto quit;
  1209.                     }
  1210.                     addHeader:
  1211.                    
  1212.                     if (headerValueStartOffset >= 0 && headerValueStartOffset > headerNameEndOffset && headerValueEndOffset >= headerValueStartOffset) {
  1213.                         //
  1214.                         // Encoding fastest way to build the UNICODE string off the byte[]
  1215.                         //
  1216.                         headerValue = HeaderEncoding.GetString(byteBuffer + headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1);
  1217.                     }
  1218.                    
  1219.                     //
  1220.                     // if we got here from the beginning of the for loop, headerMultiLineValue will be null
  1221.                     // otherwise it will contain the headerValue constructed for the multiline header
  1222.                     // add this line as well to it, separated by a single space
  1223.                     //
  1224.                     headerMultiLineValue = (headerMultiLineValue == null ? headerValue : headerMultiLineValue + " " + headerValue);
  1225.                    
  1226.                     if (index < size && numberOfLf == 1) {
  1227.                         ch = (char)byteBuffer[index];
  1228.                         if (ch == ' ' || ch == '\t') {
  1229.                             //
  1230.                             // since we found only one Lf and the next header line begins with a Lws,
  1231.                             // this is the beginning of a multiline header.
  1232.                             // parse the next line into headerValue later it will be added to headerMultiLineValue
  1233.                             //
  1234.                             ++index;
  1235.                             if (maximumResponseHeadersLength >= 0 && ++localTotalResponseHeadersLength >= maximumResponseHeadersLength) {
  1236.                                 parseStatus = DataParseStatus.DataTooBig;
  1237.                                 goto quit;
  1238.                             }
  1239.                             goto startOfValue;
  1240.                         }
  1241.                     }
  1242.                    
  1243.                     if (headerNameStartOffset >= 0 && headerNameEndOffset >= headerNameStartOffset) {
  1244.                         //
  1245.                         // Encoding is the fastest way to build the UNICODE string off the byte[]
  1246.                         //
  1247.                         headerName = HeaderEncoding.GetString(byteBuffer + headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1);
  1248.                     }
  1249.                    
  1250.                     //
  1251.                     // now it's finally safe to add the header if we have a name for it
  1252.                     //
  1253.                     if (headerName.Length > 0) {
  1254.                         //
  1255.                         // the base clasee will check for pre-existing headerValue and append
  1256.                         // it using commas as indicated in the RFC
  1257.                         //
  1258.                         GlobalLog.Print("WebHeaderCollection::ParseHeaders() calling AddInternal() key:[" + headerName + "], value:[" + headerMultiLineValue + "]");
  1259.                         AddInternal(headerName, headerMultiLineValue);
  1260.                     }
  1261.                    
  1262.                     //
  1263.                     // and update unparsed
  1264.                     //
  1265.                     totalResponseHeadersLength = localTotalResponseHeadersLength;
  1266.                     unparsed = index;
  1267.                    
  1268.                     if (numberOfLf == 2) {
  1269.                         parseStatus = DataParseStatus.Done;
  1270.                         goto quit;
  1271.                     }
  1272.                    
  1273.                 }
  1274.                 quit:
  1275.                 // for (;;)
  1276.                 GlobalLog.Leave("WebHeaderCollection::ParseHeaders() returning parseStatus:" + parseStatus.ToString());
  1277.                 if (parseStatus == DataParseStatus.Invalid) {
  1278.                     parseError.Section = WebParseErrorSection.ResponseHeader;
  1279.                     parseError.Code = parseErrorCode;
  1280.                 }
  1281.                
  1282.                 return parseStatus;
  1283.             }
  1284.         }
  1285.        
  1286.         //
  1287.         // Alternative parsing that follows RFC2616. Like the above, this trims both sides of the header value and replaces
  1288.         // folding with a single space.
  1289.         //
  1290.         private enum RfcChar : byte
  1291.         {
  1292.             High = 0,
  1293.             Reg,
  1294.             Ctl,
  1295.             CR,
  1296.             LF,
  1297.             WS,
  1298.             Colon,
  1299.             Delim
  1300.         }
  1301.        
  1302.         private static RfcChar[] RfcCharMap = new RfcChar[128] {RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.WS,
  1303.         RfcChar.LF, RfcChar.Ctl, RfcChar.Ctl, RfcChar.CR, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl,
  1304.         RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl, RfcChar.Ctl,
  1305.         RfcChar.Ctl, RfcChar.Ctl, RfcChar.WS, RfcChar.Reg, RfcChar.Delim, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1306.         RfcChar.Delim, RfcChar.Delim, RfcChar.Reg, RfcChar.Reg, RfcChar.Delim, RfcChar.Reg, RfcChar.Reg, RfcChar.Delim, RfcChar.Reg, RfcChar.Reg,
  1307.         RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Colon, RfcChar.Delim,
  1308.         RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1309.         RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1310.         RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1311.         RfcChar.Reg, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1312.         RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1313.         RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Reg,
  1314.         RfcChar.Reg, RfcChar.Reg, RfcChar.Reg, RfcChar.Delim, RfcChar.Reg, RfcChar.Delim, RfcChar.Reg, RfcChar.Ctl};
  1315.        
  1316.         unsafe internal DataParseStatus ParseHeadersStrict(byte[] buffer, int size, ref int unparsed, ref int totalResponseHeadersLength, int maximumResponseHeadersLength, ref WebParseError parseError)
  1317.         {
  1318.             GlobalLog.Enter("WebHeaderCollection::ParseHeadersStrict(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size - unparsed)) + "]");
  1319.            
  1320.             WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic;
  1321.             DataParseStatus parseStatus = DataParseStatus.Invalid;
  1322.            
  1323.             int i = unparsed;
  1324.             RfcChar ch;
  1325.             int effectiveSize = maximumResponseHeadersLength <= 0 ? Int32.MaxValue : maximumResponseHeadersLength - totalResponseHeadersLength + i;
  1326.             DataParseStatus sizeError = DataParseStatus.DataTooBig;
  1327.             if (size < effectiveSize) {
  1328.                 effectiveSize = size;
  1329.                 sizeError = DataParseStatus.NeedMoreData;
  1330.             }
  1331.            
  1332.             // Verify the size.
  1333.             if (i >= effectiveSize) {
  1334.                 parseStatus = sizeError;
  1335.                 goto quit;
  1336.             }
  1337.            
  1338.             fixed (byte* byteBuffer = buffer) {
  1339.                 while (true) {
  1340.                     // If this is CRLF, actually we're done.
  1341.                     if (byteBuffer[i] == '\r') {
  1342.                         if (++i == effectiveSize) {
  1343.                             parseStatus = sizeError;
  1344.                             goto quit;
  1345.                         }
  1346.                        
  1347.                         if (byteBuffer[i++] == '\n') {
  1348.                             totalResponseHeadersLength += i - unparsed;
  1349.                             unparsed = i;
  1350.                             parseStatus = DataParseStatus.Done;
  1351.                             goto quit;
  1352.                         }
  1353.                        
  1354.                         parseStatus = DataParseStatus.Invalid;
  1355.                         parseErrorCode = WebParseErrorCode.CrLfError;
  1356.                         goto quit;
  1357.                     }
  1358.                    
  1359.                     // Find the header name; only regular characters allowed.
  1360.                     int iBeginName = i;
  1361.                     for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.Reg; i++)
  1362.                         ;
  1363.                     if (i == effectiveSize) {
  1364.                         parseStatus = sizeError;
  1365.                         goto quit;
  1366.                     }
  1367.                     if (i == iBeginName) {
  1368.                         parseStatus = DataParseStatus.Invalid;
  1369.                         parseErrorCode = WebParseErrorCode.InvalidHeaderName;
  1370.                         goto quit;
  1371.                     }
  1372.                    
  1373.                     // Read to a colon.
  1374.                     int iEndName = i - 1;
  1375.                     int crlf = 0;
  1376.                     // 1 = cr, 2 = crlf
  1377.                     for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) != RfcChar.Colon; i++) {
  1378.                         switch (ch) {
  1379.                             case RfcChar.WS:
  1380.                                 if (crlf == 1) {
  1381.                                     break;
  1382.                                 }
  1383.                                 crlf = 0;
  1384.                                 continue;
  1385.                             case RfcChar.CR:
  1386.                                
  1387.                                 if (crlf == 0) {
  1388.                                     crlf = 1;
  1389.                                     continue;
  1390.                                 }
  1391.                                 break;
  1392.                             case RfcChar.LF:
  1393.                                
  1394.                                 if (crlf == 1) {
  1395.                                     crlf = 2;
  1396.                                     continue;
  1397.                                 }
  1398.                                 break;
  1399.                         }
  1400.                         parseStatus = DataParseStatus.Invalid;
  1401.                         parseErrorCode = WebParseErrorCode.CrLfError;
  1402.                         goto quit;
  1403.                     }
  1404.                     if (i == effectiveSize) {
  1405.                         parseStatus = sizeError;
  1406.                         goto quit;
  1407.                     }
  1408.                     if (crlf != 0) {
  1409.                         parseStatus = DataParseStatus.Invalid;
  1410.                         parseErrorCode = WebParseErrorCode.IncompleteHeaderLine;
  1411.                         goto quit;
  1412.                     }
  1413.                    
  1414.                     // Skip the colon.
  1415.                     if (++i == effectiveSize) {
  1416.                         parseStatus = sizeError;
  1417.                         goto quit;
  1418.                     }
  1419.                    
  1420.                     // Read the value. crlf = 3 means in the whitespace after a CRLF
  1421.                     int iBeginValue = -1;
  1422.                     int iEndValue = -1;
  1423.                     StringBuilder valueAccumulator = null;
  1424.                     for (; i < effectiveSize && ((ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.WS || crlf != 2); i++) {
  1425.                         switch (ch) {
  1426.                             case RfcChar.WS:
  1427.                                 if (crlf == 1) {
  1428.                                     break;
  1429.                                 }
  1430.                                 if (crlf == 2) {
  1431.                                     crlf = 3;
  1432.                                 }
  1433.                                 continue;
  1434.                             case RfcChar.CR:
  1435.                                
  1436.                                 if (crlf == 0) {
  1437.                                     crlf = 1;
  1438.                                     continue;
  1439.                                 }
  1440.                                 break;
  1441.                             case RfcChar.LF:
  1442.                                
  1443.                                 if (crlf == 1) {
  1444.                                     crlf = 2;
  1445.                                     continue;
  1446.                                 }
  1447.                                 break;
  1448.                             case RfcChar.High:
  1449.                             case RfcChar.Colon:
  1450.                             case RfcChar.Delim:
  1451.                             case RfcChar.Reg:
  1452.                                
  1453.                                 if (crlf == 1) {
  1454.                                     break;
  1455.                                 }
  1456.                                 if (crlf == 3) {
  1457.                                     crlf = 0;
  1458.                                     if (iBeginValue != -1) {
  1459.                                         string s = HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1);
  1460.                                         if (valueAccumulator == null) {
  1461.                                             valueAccumulator = new StringBuilder(s, s.Length * 5);
  1462.                                         }
  1463.                                         else {
  1464.                                             valueAccumulator.Append(" ");
  1465.                                             valueAccumulator.Append(s);
  1466.                                         }
  1467.                                     }
  1468.                                     iBeginValue = -1;
  1469.                                 }
  1470.                                 if (iBeginValue == -1) {
  1471.                                     iBeginValue = i;
  1472.                                 }
  1473.                                 iEndValue = i;
  1474.                                 continue;
  1475.                         }
  1476.                         parseStatus = DataParseStatus.Invalid;
  1477.                         parseErrorCode = WebParseErrorCode.CrLfError;
  1478.                         goto quit;
  1479.                     }
  1480.                     if (i == effectiveSize) {
  1481.                         parseStatus = sizeError;
  1482.                         goto quit;
  1483.                     }
  1484.                    
  1485.                     // Make the value.
  1486.                     string sValue = iBeginValue == -1 ? "" : HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1);
  1487.                     if (valueAccumulator != null) {
  1488.                         if (sValue.Length != 0) {
  1489.                             valueAccumulator.Append(" ");
  1490.                             valueAccumulator.Append(sValue);
  1491.                         }
  1492.                         sValue = valueAccumulator.ToString();
  1493.                     }
  1494.                    
  1495.                     // Make the name. See if it's a common header first.
  1496.                     string sName = null;
  1497.                     int headerNameLength = iEndName - iBeginName + 1;
  1498.                     if (m_CommonHeaders != null) {
  1499.                         int iHeader = s_CommonHeaderHints[byteBuffer[iBeginName] & 31];
  1500.                         if (iHeader >= 0) {
  1501.                             while (true) {
  1502.                                 string s = s_CommonHeaderNames[iHeader++];
  1503.                                
  1504.                                 // Not found if we get to a shorter header or one with a different first character.
  1505.                                 if (s.Length < headerNameLength || CaseInsensitiveAscii.AsciiToLower[byteBuffer[iBeginName]] != CaseInsensitiveAscii.AsciiToLower[s[0]])
  1506.                                     break;
  1507.                                
  1508.                                 // Keep looking if the common header is too long.
  1509.                                 if (s.Length > headerNameLength)
  1510.                                     continue;
  1511.                                
  1512.                                 int j;
  1513.                                 byte* pBuffer = byteBuffer + iBeginName + 1;
  1514.                                 for (j = 1; j < s.Length; j++) {
  1515.                                     // Avoid the case-insensitive compare in the common case where they match.
  1516.                                     if (*(pBuffer++) != s[j] && CaseInsensitiveAscii.AsciiToLower[*(pBuffer - 1)] != CaseInsensitiveAscii.AsciiToLower[s[j]])
  1517.                                         break;
  1518.                                 }
  1519.                                 if (j == s.Length) {
  1520.                                     // Set it to the appropriate index.
  1521.                                     m_NumCommonHeaders++;
  1522.                                     iHeader--;
  1523.                                     if (m_CommonHeaders[iHeader] == null) {
  1524.                                         m_CommonHeaders[iHeader] = sValue;
  1525.                                     }
  1526.                                     else {
  1527.                                         // Don't currently handle combining multiple header instances in the common header case.
  1528.                                         // Nothing to do but punt them all to the NameValueCollection.
  1529.                                         NormalizeCommonHeaders();
  1530.                                         AddInternalNotCommon(s, sValue);
  1531.                                     }
  1532.                                    
  1533.                                     sName = s;
  1534.                                     break;
  1535.                                 }
  1536.                             }
  1537.                         }
  1538.                     }
  1539.                    
  1540.                     // If it wasn't a common header, add it to the hash.
  1541.                     if (sName == null) {
  1542.                         sName = HeaderEncoding.GetString(byteBuffer + iBeginName, headerNameLength);
  1543.                         AddInternalNotCommon(sName, sValue);
  1544.                     }
  1545.                    
  1546.                     totalResponseHeadersLength += i - unparsed;
  1547.                     unparsed = i;
  1548.                 }
  1549.             }
  1550.             quit:
  1551.            
  1552.             GlobalLog.Leave("WebHeaderCollection::ParseHeadersStrict() returning parseStatus:" + parseStatus.ToString());
  1553.            
  1554.             if (parseStatus == DataParseStatus.Invalid) {
  1555.                 parseError.Section = WebParseErrorSection.ResponseHeader;
  1556.                 parseError.Code = parseErrorCode;
  1557.             }
  1558.            
  1559.             return parseStatus;
  1560.         }
  1561.        
  1562.         //
  1563.         // Keeping this version for backwards compatibility (mostly with reflection). Remove some day, along with the interface
  1564.         // explicit reimplementation.
  1565.         //
  1566.         /// <internalonly/>
  1567.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
  1568.         void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
  1569.         {
  1570.             GetObjectData(serializationInfo, streamingContext);
  1571.         }
  1572.        
  1573.         // Override Get() to check the common headers.
  1574.         public override string Get(string name)
  1575.         {
  1576.             // In this case, need to make sure name doesn't have any Unicode since it's being used as an index into tables.
  1577.             if (m_CommonHeaders != null && name != null && name.Length > 0 && name[0] < 256) {
  1578.                 int iHeader = s_CommonHeaderHints[name[0] & 31];
  1579.                 if (iHeader >= 0) {
  1580.                     while (true) {
  1581.                         string s = s_CommonHeaderNames[iHeader++];
  1582.                        
  1583.                         // Not found if we get to a shorter header or one with a different first character.
  1584.                         if (s.Length < name.Length || CaseInsensitiveAscii.AsciiToLower[name[0]] != CaseInsensitiveAscii.AsciiToLower[s[0]])
  1585.                             break;
  1586.                        
  1587.                         // Keep looking if the common header is too long.
  1588.                         if (s.Length > name.Length)
  1589.                             continue;
  1590.                        
  1591.                         int j;
  1592.                         for (j = 1; j < s.Length; j++) {
  1593.                             // Avoid the case-insensitive compare in the common case where they match.
  1594.                             if (name[j] != s[j] && (name[j] > 255 || CaseInsensitiveAscii.AsciiToLower[name[j]] != CaseInsensitiveAscii.AsciiToLower[s[j]]))
  1595.                                 break;
  1596.                         }
  1597.                         if (j == s.Length) {
  1598.                             // Get the appropriate header.
  1599.                             return m_CommonHeaders[iHeader - 1];
  1600.                         }
  1601.                     }
  1602.                 }
  1603.             }
  1604.            
  1605.             // Fall back to normal lookup.
  1606.             if (m_InnerCollection == null)
  1607.                 return null;
  1608.             return m_InnerCollection.Get(name);
  1609.         }
  1610.        
  1611.        
  1612.         //
  1613.         // Additional overrides required to fully orphan the base implementation.
  1614.         //
  1615.         public override IEnumerator GetEnumerator()
  1616.         {
  1617.             NormalizeCommonHeaders();
  1618.             return new NameObjectKeysEnumerator(InnerCollection);
  1619.         }
  1620.        
  1621.         public override int Count {
  1622.             get { return (m_InnerCollection == null ? 0 : m_InnerCollection.Count) + m_NumCommonHeaders; }
  1623.         }
  1624.        
  1625.         public override KeysCollection Keys {
  1626.             get {
  1627.                 NormalizeCommonHeaders();
  1628.                 return InnerCollection.Keys;
  1629.             }
  1630.         }
  1631.        
  1632.         internal override bool InternalHasKeys()
  1633.         {
  1634.             NormalizeCommonHeaders();
  1635.             if (m_InnerCollection == null)
  1636.                 return false;
  1637.             return m_InnerCollection.HasKeys();
  1638.         }
  1639.        
  1640.         public override string Get(int index)
  1641.         {
  1642.             NormalizeCommonHeaders();
  1643.             return InnerCollection.Get(index);
  1644.         }
  1645.        
  1646.         public override string[] GetValues(int index)
  1647.         {
  1648.             NormalizeCommonHeaders();
  1649.             return InnerCollection.GetValues(index);
  1650.         }
  1651.        
  1652.         public override string GetKey(int index)
  1653.         {
  1654.             NormalizeCommonHeaders();
  1655.             return InnerCollection.GetKey(index);
  1656.         }
  1657.        
  1658.         public override string[] AllKeys {
  1659.             get {
  1660.                 NormalizeCommonHeaders();
  1661.                 return InnerCollection.AllKeys;
  1662.             }
  1663.         }
  1664.        
  1665.         public override void Clear()
  1666.         {
  1667.             m_CommonHeaders = null;
  1668.             m_NumCommonHeaders = 0;
  1669.             InvalidateCachedArrays();
  1670.             if (m_InnerCollection != null)
  1671.                 m_InnerCollection.Clear();
  1672.         }
  1673.     }
  1674.     // class WebHeaderCollection
  1675.    
  1676.     internal class CaseInsensitiveAscii : IEqualityComparer, IComparer
  1677.     {
  1678.         // ASCII char ToLower table
  1679.         static internal readonly CaseInsensitiveAscii StaticInstance = new CaseInsensitiveAscii();
  1680.         static internal readonly byte[] AsciiToLower = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  1681.         10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  1682.         20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  1683.         30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
  1684.         40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
  1685.         50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
  1686.         60, 61, 62, 63, 64, 97, 98, 99, 100, 101,
  1687.         102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  1688.         112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
  1689.         122, 91, 92, 93, 94, 95, 96, 97, 98, 99,
  1690.         100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
  1691.         110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
  1692.         120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
  1693.         130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
  1694.         140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
  1695.         150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  1696.         160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
  1697.         170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
  1698.         180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
  1699.         190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
  1700.         200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
  1701.         210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
  1702.         220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
  1703.         230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
  1704.         240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
  1705.             // 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
  1706.             // 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  1707.             // 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
  1708.             // 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
  1709.         250, 251, 252, 253, 254, 255};
  1710.        
  1711.         // ASCII string case insensitive hash function
  1712.         public int GetHashCode(object myObject)
  1713.         {
  1714.             string myString = myObject as string;
  1715.             if (myObject == null) {
  1716.                 return 0;
  1717.             }
  1718.             int myHashCode = myString.Length;
  1719.             if (myHashCode == 0) {
  1720.                 return 0;
  1721.             }
  1722.             myHashCode ^= AsciiToLower[(byte)myString[0]] << 24 ^ AsciiToLower[(byte)myString[myHashCode - 1]] << 16;
  1723.             return myHashCode;
  1724.         }
  1725.        
  1726.         // ASCII string case insensitive comparer
  1727.         public int Compare(object firstObject, object secondObject)
  1728.         {
  1729.             string firstString = firstObject as string;
  1730.             string secondString = secondObject as string;
  1731.             if (firstString == null) {
  1732.                 return secondString == null ? 0 : -1;
  1733.             }
  1734.             if (secondString == null) {
  1735.                 return 1;
  1736.             }
  1737.             int result = firstString.Length - secondString.Length;
  1738.             int comparisons = result > 0 ? secondString.Length : firstString.Length;
  1739.             int difference;
  1740.             int index = 0;
  1741.             while (index < comparisons) {
  1742.                 difference = (int)(AsciiToLower[firstString[index]] - AsciiToLower[secondString[index]]);
  1743.                 if (difference != 0) {
  1744.                     result = difference;
  1745.                     break;
  1746.                 }
  1747.                 index++;
  1748.             }
  1749.             return result;
  1750.         }
  1751.        
  1752.         // ASCII string case insensitive hash function
  1753.         int FastGetHashCode(string myString)
  1754.         {
  1755.             int myHashCode = myString.Length;
  1756.             if (myHashCode != 0) {
  1757.                 myHashCode ^= AsciiToLower[(byte)myString[0]] << 24 ^ AsciiToLower[(byte)myString[myHashCode - 1]] << 16;
  1758.             }
  1759.             return myHashCode;
  1760.         }
  1761.        
  1762.         // ASCII string case insensitive comparer
  1763.         public new bool Equals(object firstObject, object secondObject)
  1764.         {
  1765.             string firstString = firstObject as string;
  1766.             string secondString = secondObject as string;
  1767.             if (firstString == null) {
  1768.                 return secondString == null;
  1769.             }
  1770.             if (secondString != null) {
  1771.                 int index = firstString.Length;
  1772.                 if (index == secondString.Length) {
  1773.                     if (FastGetHashCode(firstString) == FastGetHashCode(secondString)) {
  1774.                         int comparisons = firstString.Length;
  1775.                         while (index > 0) {
  1776.                             index--;
  1777.                             if (AsciiToLower[firstString[index]] != AsciiToLower[secondString[index]]) {
  1778.                                 return false;
  1779.                             }
  1780.                         }
  1781.                         return true;
  1782.                     }
  1783.                 }
  1784.             }
  1785.             return false;
  1786.         }
  1787.     }
  1788. }

Developer Fusion