WebHeaderCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Net / System / Net / WebHeaderCollection.cs / 1 / WebHeaderCollection.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net { 
    using System.Net.Cache; 
    using System.Collections;
    using System.Collections.Specialized; 
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Globalization; 
    using System.Security.Permissions;
 
    internal enum WebHeaderCollectionType : ushort { 
        Unknown,
        WebRequest, 
        WebResponse,
        HttpWebRequest,
        HttpWebResponse,
        HttpListenerRequest, 
        HttpListenerResponse,
        FtpWebRequest, 
        FtpWebResponse, 
        FileWebRequest,
        FileWebResponse, 
    }

    //
    // HttpHeaders - this is our main HttpHeaders object, 
    //  which is a simple collection of name-value pairs,
    //  along with additional methods that provide HTTP parsing 
    //  collection to sendable buffer capablities and other enhansments 
    //  We also provide validation of what headers are allowed to be added.
    // 

    /// 
    ///    
    ///       Contains protocol headers associated with a 
    ///       request or response.
    ///     
    ///  
    [ComVisible(true), Serializable]
    public class WebHeaderCollection : NameValueCollection, ISerializable { 
        //
        // Data and Constants
        //
        private const int ApproxAveHeaderLineSize = 30; 
        private const int ApproxHighAvgNumHeaders = 16;
        private static readonly HeaderInfoTable HInfo = new HeaderInfoTable(); 
 
        //
        // Common Headers - used only when receiving a response, and internally.  If the user ever requests a header, 
        // all the common headers are moved into the hashtable.
        //
        private string[] m_CommonHeaders;
        private int m_NumCommonHeaders; 

        // Grouped by first character, so lookup is faster.  The table s_CommonHeaderHints maps first letters to indexes in this array. 
        // After first character, sort by decreasing length.  It's ok if two headers have the same first character and length. 
        private static readonly string[] s_CommonHeaderNames = new string[] {
            HttpKnownHeaderNames.AcceptRanges,      // "Accept-Ranges"       13 
            HttpKnownHeaderNames.ContentLength,     // "Content-Length"      14
            HttpKnownHeaderNames.CacheControl,      // "Cache-Control"       13
            HttpKnownHeaderNames.ContentType,       // "Content-Type"        12
            HttpKnownHeaderNames.Date,              // "Date"                 4 
            HttpKnownHeaderNames.Expires,           // "Expires"              7
            HttpKnownHeaderNames.ETag,              // "ETag"                 4 
            HttpKnownHeaderNames.LastModified,      // "Last-Modified"       13 
            HttpKnownHeaderNames.Location,          // "Location"             8
            HttpKnownHeaderNames.ProxyAuthenticate, // "Proxy-Authenticate"  18 
            HttpKnownHeaderNames.P3P,               // "P3P"                  3
            HttpKnownHeaderNames.SetCookie2,        // "Set-Cookie2"         11
            HttpKnownHeaderNames.SetCookie,         // "Set-Cookie"          10
            HttpKnownHeaderNames.Server,            // "Server"               6 
            HttpKnownHeaderNames.Via,               // "Via"                  3
            HttpKnownHeaderNames.WWWAuthenticate,   // "WWW-Authenticate"    16 
            HttpKnownHeaderNames.XAspNetVersion,    // "X-AspNet-Version"    16 
            HttpKnownHeaderNames.XPoweredBy,        // "X-Powered-By"        12
            "[" };  // This sentinel will never match.  (This character isn't in the hint table.) 

        // Mask off all but the bottom five bits, and look up in this array.
        private static readonly sbyte[] s_CommonHeaderHints = new sbyte[] {
            -1,  0, -1,  1,  4,  5, -1, -1,   // - a b c d e f g 
            -1, -1, -1, -1,  7, -1, -1, -1,   // h i j k l m n o
             9, -1, -1, 11, -1, -1, 14, 15,   // p q r s t u v w 
            16, -1, -1, -1, -1, -1, -1, -1 }; // x y z [ - - - - 

        private const int c_AcceptRanges      =  0; 
        private const int c_ContentLength     =  1;
        private const int c_CacheControl      =  2;
        private const int c_ContentType       =  3;
        private const int c_Date              =  4; 
        private const int c_Expires           =  5;
        private const int c_ETag              =  6; 
        private const int c_LastModified      =  7; 
        private const int c_Location          =  8;
        private const int c_ProxyAuthenticate =  9; 
        private const int c_P3P               = 10;
        private const int c_SetCookie2        = 11;
        private const int c_SetCookie         = 12;
        private const int c_Server            = 13; 
        private const int c_Via               = 14;
        private const int c_WwwAuthenticate   = 15; 
        private const int c_XAspNetVersion    = 16; 
        private const int c_XPoweredBy        = 17;
 
        // Easy fast lookups for common headers.  More can be added.
        internal string ContentLength
        {
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_ContentLength] : Get(s_CommonHeaderNames[c_ContentLength]); 
            } 
        }
 
        internal string CacheControl
        {
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_CacheControl] : Get(s_CommonHeaderNames[c_CacheControl]);
            } 
        } 

        internal string ContentType 
        {
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_ContentType] : Get(s_CommonHeaderNames[c_ContentType]); 
            }
        } 
 
        internal string Date
        { 
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Date] : Get(s_CommonHeaderNames[c_Date]);
            } 
        }
 
        internal string Expires 
        {
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Expires] : Get(s_CommonHeaderNames[c_Expires]);
            }
        } 

        internal string ETag 
        { 
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_ETag] : Get(s_CommonHeaderNames[c_ETag]);
            }
        }
 
        internal string LastModified
        { 
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_LastModified] : Get(s_CommonHeaderNames[c_LastModified]); 
            }
        }

        internal string Location 
        {
            get 
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_Location] : Get(s_CommonHeaderNames[c_Location]);
            } 
        }

        internal string ProxyAuthenticate
        { 
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_ProxyAuthenticate] : Get(s_CommonHeaderNames[c_ProxyAuthenticate]); 
            }
        } 

        internal string SetCookie2
        {
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_SetCookie2] : Get(s_CommonHeaderNames[c_SetCookie2]); 
            } 
        }
 
        internal string SetCookie
        {
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_SetCookie] : Get(s_CommonHeaderNames[c_SetCookie]);
            } 
        } 

        internal string Server 
        {
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Server] : Get(s_CommonHeaderNames[c_Server]); 
            }
        } 
 
        internal string Via
        { 
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Via] : Get(s_CommonHeaderNames[c_Via]);
            } 
        }
 
        private void NormalizeCommonHeaders() 
        {
            if (m_CommonHeaders == null) 
                return;
            for (int i = 0; i < m_CommonHeaders.Length; i++)
                if (m_CommonHeaders[i] != null)
                    InnerCollection.Add(s_CommonHeaderNames[i], m_CommonHeaders[i]); 

            m_CommonHeaders = null; 
            m_NumCommonHeaders = 0; 
        }
 
        //
        // To ensure C++ and IL callers can't pollute the underlying collection by calling overridden base members directly, we
        // will use a member collection instead.
        private NameValueCollection m_InnerCollection; 

        private NameValueCollection InnerCollection 
        { 
            get
            { 
                if (m_InnerCollection == null)
                    m_InnerCollection = new NameValueCollection(ApproxHighAvgNumHeaders, CaseInsensitiveAscii.StaticInstance);
                return m_InnerCollection;
            } 
        }
 
        // this is the object that created the header collection. 
        private WebHeaderCollectionType m_Type;
 
#if !FEATURE_PAL
        private bool AllowHttpRequestHeader {
            get {
                if (m_Type==WebHeaderCollectionType.Unknown) { 
                    m_Type = WebHeaderCollectionType.WebRequest;
                } 
                return m_Type==WebHeaderCollectionType.WebRequest || m_Type==WebHeaderCollectionType.HttpWebRequest || m_Type==WebHeaderCollectionType.HttpListenerRequest; 
            }
        } 

        internal bool AllowHttpResponseHeader {
            get {
                if (m_Type==WebHeaderCollectionType.Unknown) { 
                    m_Type = WebHeaderCollectionType.WebResponse;
                } 
                return m_Type==WebHeaderCollectionType.WebResponse || m_Type==WebHeaderCollectionType.HttpWebResponse || m_Type==WebHeaderCollectionType.HttpListenerResponse; 
            }
        } 

        public string this[HttpRequestHeader header] {
            get {
                if (!AllowHttpRequestHeader) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
                } 
                return this[UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header)]; 
            }
            set { 
                if (!AllowHttpRequestHeader) {
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
                }
                this[UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header)] = value; 
            }
        } 
        public string this[HttpResponseHeader header] { 
            get {
                if (!AllowHttpResponseHeader) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
                }

                // Some of these can be mapped to Common Headers.  Other cases can be added as needed for perf. 
                if (m_CommonHeaders != null)
                { 
                    switch (header) 
                    {
                        case HttpResponseHeader.ProxyAuthenticate: 
                            return m_CommonHeaders[c_ProxyAuthenticate];

                        case HttpResponseHeader.WwwAuthenticate:
                            return m_CommonHeaders[c_WwwAuthenticate]; 
                    }
                } 
 
                return this[UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header)];
            } 
            set {
                if (!AllowHttpResponseHeader) {
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
                } 
                if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                    if (value!=null && value.Length>ushort.MaxValue) { 
                        throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                    }
                } 
                this[UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header)] = value;
            }
        }
 
        public void Add(HttpRequestHeader header, string value) {
            if (!AllowHttpRequestHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_req)); 
            }
            this.Add(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header), value); 
        }

        public void Add(HttpResponseHeader header, string value) {
            if (!AllowHttpResponseHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
            } 
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                }
            }
            this.Add(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header), value);
        } 

        public void Set(HttpRequestHeader header, string value) { 
            if (!AllowHttpRequestHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
            } 
            this.Set(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header), value);
        }

        public void Set(HttpResponseHeader header, string value) { 
            if (!AllowHttpResponseHeader) {
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp)); 
            } 
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                }
            }
            this.Set(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header), value); 
        }
 
 
        internal void SetInternal(HttpResponseHeader header, string value) {
            if (!AllowHttpResponseHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
            }
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                } 
            } 
            this.SetInternal(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header), value);
        } 


        public void Remove(HttpRequestHeader header) {
            if (!AllowHttpRequestHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
            } 
            this.Remove(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header)); 
        }
 
        public void Remove(HttpResponseHeader header) {
            if (!AllowHttpResponseHeader) {
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
            } 
            this.Remove(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header));
        } 
#endif // !FEATURE_PAL 

        // In general, HttpWebResponse headers aren't modified, so these methods don't support common headers. 

        /// 
        ///    [To be supplied.]
        ///  
        protected void AddWithoutValidate(string headerName, string headerValue) {
            headerName = CheckBadChars(headerName, false); 
            headerValue = CheckBadChars(headerValue, true); 
            GlobalLog.Print("WebHeaderCollection::AddWithoutValidate() calling InnerCollection.Add() key:[" + headerName + "], value:[" + headerValue + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (headerValue!=null && headerValue.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                }
            } 
            NormalizeCommonHeaders();
            InvalidateCachedArrays(); 
            InnerCollection.Add(headerName, headerValue); 
        }
 
        internal void SetAddVerified(string name, string value) {
            if(HInfo[name].AllowMultiValues) {
                GlobalLog.Print("WebHeaderCollection::SetAddVerified() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
                NormalizeCommonHeaders(); 
                InvalidateCachedArrays();
                InnerCollection.Add(name, value); 
            } 
            else {
                GlobalLog.Print("WebHeaderCollection::SetAddVerified() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]"); 
                NormalizeCommonHeaders();
                InvalidateCachedArrays();
                InnerCollection.Set(name, value);
            } 
        }
 
        // Below three methods are for fast headers manipulation, bypassing all the checks 
        internal void AddInternal(string name, string value) {
            GlobalLog.Print("WebHeaderCollection::AddInternal() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]"); 
            NormalizeCommonHeaders();
            InvalidateCachedArrays();
            InnerCollection.Add(name, value);
        } 

        internal void ChangeInternal(string name, string value) { 
            GlobalLog.Print("WebHeaderCollection::ChangeInternal() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]"); 
            NormalizeCommonHeaders();
            InvalidateCachedArrays(); 
            InnerCollection.Set(name, value);
        }

 
        internal void RemoveInternal(string name) {
            GlobalLog.Print("WebHeaderCollection::RemoveInternal() calling InnerCollection.Remove() key:[" + name + "]"); 
            NormalizeCommonHeaders(); 
            if (m_InnerCollection != null)
            { 
                InvalidateCachedArrays();
                m_InnerCollection.Remove(name);
            }
        } 

        internal void CheckUpdate(string name, string value) { 
            value = CheckBadChars(value, true); 
            ChangeInternal(name, value);
        } 

        // 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.
        private void AddInternalNotCommon(string name, string value)
        { 
            GlobalLog.Print("WebHeaderCollection::AddInternalNotCommon() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
            InvalidateCachedArrays(); 
            InnerCollection.Add(name, value); 
        }
 

        private static readonly char[] HttpTrimCharacters = new char[]{(char)0x09,(char)0xA,(char)0xB,(char)0xC,(char)0xD,(char)0x20};

        // 
        // CheckBadChars - throws on invalid chars to be not found in header name/value
        // 
        internal static string CheckBadChars(string name, bool isHeaderValue) { 

            if (name == null || name.Length == 0) { 
                // emtpy name is invlaid
                if (!isHeaderValue) {
                    throw name == null ? new ArgumentNullException("name") :
                        new ArgumentException(SR.GetString(SR.net_emptystringcall, "name"), "name"); 
                }
                //empty value is OK 
                return string.Empty; 
            }
 
            if (isHeaderValue) {
                // VALUE check
                //Trim spaces from both ends
                name = name.Trim(HttpTrimCharacters); 

                //First, check for correctly formed multi-line value 
                //Second, check for absenece of CTL characters 
                int crlf = 0;
                for(int i = 0; i < name.Length; ++i) { 
                    char c = (char) (0x000000ff & (uint) name[i]);
                    switch (crlf)
                    {
                        case 0: 
                            if (c == '\r')
                            { 
                                crlf = 1; 
                            }
                            else if (c == '\n') 
                            {
                                // Technically this is bad HTTP.  But it would be a breaking change to throw here.
                                // Is there an exploit?
                                crlf = 2; 
                            }
                            else if (c == 127 || (c < ' ' && c != '\t')) 
                            { 
                                throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidControlChars), "value");
                            } 
                            break;

                        case 1:
                            if (c == '\n') 
                            {
                                crlf = 2; 
                                break; 
                            }
                            throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value"); 

                        case 2:
                            if (c == ' ' || c == '\t')
                            { 
                                crlf = 0;
                                break; 
                            } 
                            throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value");
                    } 
                }
                if (crlf != 0)
                {
                    throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value"); 
                }
            } 
            else { 
                // NAME check
                //First, check for absence of separators and spaces 
                if (name.IndexOfAny(ValidationHelper.InvalidParamChars) != -1) {
                    throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidHeaderChars), "name");
                }
 
                //Second, check for non CTL ASCII-7 characters (32-126)
                if (ContainsNonAsciiChars(name)) { 
                    throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidNonAsciiChars), "name"); 
                }
            } 
            return name;
        }

        internal static bool IsValidToken(string token) { 
            return (token.Length > 0)
                && (token.IndexOfAny(ValidationHelper.InvalidParamChars) == -1) 
                && !ContainsNonAsciiChars(token); 
        }
 
        internal static bool ContainsNonAsciiChars(string token) {
            for (int i = 0; i < token.Length; ++i) {
                if ((token[i] < 0x20) || (token[i] > 0x7e)) {
                    return true; 
                }
            } 
            return false; 
        }
 
        //
        // ThrowOnRestrictedHeader - generates an error if the user,
        //  passed in a reserved string as the header name
        // 
        internal void ThrowOnRestrictedHeader(string headerName)
        { 
            if (m_Type == WebHeaderCollectionType.HttpWebRequest) 
            {
                if (HInfo[headerName].IsRequestRestricted) 
                {
                    throw new ArgumentException(!Equals(headerName, HttpKnownHeaderNames.Host) ? SR.GetString(SR.net_headerrestrict) :
                        SR.GetString(SR.net_headerrestrict_resp, HttpKnownHeaderNames.Host), "name");
                } 
            }
            else if (m_Type == WebHeaderCollectionType.HttpListenerResponse) 
            { 
                if (HInfo[headerName].IsResponseRestricted)
                { 
                    throw new ArgumentException(SR.GetString(SR.net_headerrestrict_resp, headerName), "name");
                }
            }
        } 

        // 
        // Our Public METHOD set, most are inherited from NameValueCollection, 
        //  not all methods from NameValueCollection are listed, even though usable -
        // 
        //  this includes
        //  Add(name, value)
        //  Add(header)
        //  this[name] {set, get} 
        //  Remove(name), returns bool
        //  Remove(name), returns void 
        //  Set(name, value) 
        //  ToString()
        // 
        //  SplitValue(name, value)
        //  ToByteArray()
        //  ParseHeaders(char [], ...)
        //  ParseHeaders(byte [], ...) 
        //
 
        // Add more headers; if "name" already exists it will 
        // add concatenated value
 

        // Add -
        //  Routine Description:
        //      Adds headers with validation to see if they are "proper" headers. 
        //      Will cause header to be concat to existing if already found.
        //      If the header is a special header, listed in RestrictedHeaders object, 
        //      then this call will cause an exception indication as such. 
        //  Arguments:
        //      name - header-name to add 
        //      value - header-value to add, a header is already there, will concat this value
        //  Return Value:
        //      None
 
        /// 
        ///     
        ///       Adds a new header with the indicated name and value. 
        ///    
        ///  
        public override void Add(string name, string value) {
            name = CheckBadChars(name, false);
            ThrowOnRestrictedHeader(name);
            value = CheckBadChars(value, true); 
            GlobalLog.Print("WebHeaderCollection::Add() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (value!=null && value.Length>ushort.MaxValue) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                } 
            }
            NormalizeCommonHeaders();
            InvalidateCachedArrays();
            InnerCollection.Add(name, value); 
        }
 
 
        // Add -
        // Routine Description: 
        //     Adds headers with validation to see if they are "proper" headers.
        //     Assumes a combined a "Name: Value" string, and parses the two parts out.
        //     Will cause header to be concat to existing if already found.
        //     If the header is a speical header, listed in RestrictedHeaders object, 
        //     then this call will cause an exception indication as such.
        // Arguments: 
        //     header - header name: value pair 
        // Return Value:
        //     None 

        /// 
        ///    
        ///       Adds the indicated header. 
        ///    
        ///  
        public void Add(string header) { 
            if ( ValidationHelper.IsBlankString(header) ) {
                throw new ArgumentNullException("header"); 
            }
            int colpos = header.IndexOf(':');
            // check for badly formed header passed in
            if (colpos<0) { 
                throw new ArgumentException(SR.GetString(SR.net_WebHeaderMissingColon), "header");
            } 
            string name = header.Substring(0, colpos); 
            string value = header.Substring(colpos+1);
            name = CheckBadChars(name, false); 
            ThrowOnRestrictedHeader(name);
            value = CheckBadChars(value, true);
            GlobalLog.Print("WebHeaderCollection::Add(" + header + ") calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                } 
            }
            NormalizeCommonHeaders(); 
            InvalidateCachedArrays();
            InnerCollection.Add(name, value);
        }
 
        // Set -
        // Routine Description: 
        //     Sets headers with validation to see if they are "proper" headers. 
        //     If the header is a special header, listed in RestrictedHeaders object,
        //     then this call will cause an exception indication as such. 
        // Arguments:
        //     name - header-name to set
        //     value - header-value to set
        // Return Value: 
        //     None
 
        ///  
        ///    
        ///       Sets the specified header to the specified value. 
        ///    
        /// 
        public override void Set(string name, string value) {
            if (ValidationHelper.IsBlankString(name)) { 
                throw new ArgumentNullException("name");
            } 
            name = CheckBadChars(name, false); 
            ThrowOnRestrictedHeader(name);
            value = CheckBadChars(value, true); 
            GlobalLog.Print("WebHeaderCollection::Set() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                }
            } 
            NormalizeCommonHeaders(); 
            InvalidateCachedArrays();
            InnerCollection.Set(name, value); 
        }


        internal void SetInternal(string name, string value) { 
            if (ValidationHelper.IsBlankString(name)) {
                throw new ArgumentNullException("name"); 
            } 
            name = CheckBadChars(name, false);
            value = CheckBadChars(value, true); 
            GlobalLog.Print("WebHeaderCollection::Set() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                }
            } 
            NormalizeCommonHeaders(); 
            InvalidateCachedArrays();
            InnerCollection.Set(name, value); 
        }


        // Remove - 
        // Routine Description:
        //     Removes give header with validation to see if they are "proper" headers. 
        //     If the header is a speical header, listed in RestrictedHeaders object, 
        //     then this call will cause an exception indication as such.
        // Arguments: 
        //     name - header-name to remove
        // Return Value:
        //     None
 
        /// 
        ///    Removes the specified header. 
        ///  
        public override void Remove(string name) {
            if ( ValidationHelper.IsBlankString(name) ) { 
                throw new ArgumentNullException("name");
            }
            ThrowOnRestrictedHeader(name);
            name = CheckBadChars(name,  false); 
            GlobalLog.Print("WebHeaderCollection::Remove() calling InnerCollection.Remove() key:[" + name + "]");
            NormalizeCommonHeaders(); 
            if (m_InnerCollection != null) 
            {
                InvalidateCachedArrays(); 
                m_InnerCollection.Remove(name);
            }
        }
 

        // GetValues 
        // Routine Description: 
        //     This method takes a header name and returns a string array representing
        //     the individual values for that headers. For example, if the headers 
        //     contained the line Accept: text/plain, text/html then
        //     GetValues("Accept") would return an array of two strings: "text/plain"
        //     and "text/html".
        // Arguments: 
        //     header      - Name of the header.
        // Return Value: 
        //     string[] - array of parsed string objects 

        ///  
        ///    
        ///       Gets an array of header values stored in a
        ///       header.
        ///     
        /// 
        public override string[] GetValues(string header) { 
            // This method doesn't work with common headers.  Dump common headers into the pool. 
            NormalizeCommonHeaders();
 
            // First get the information about the header and the values for
            // the header.
            HeaderInfo Info = HInfo[header];
            string[] Values = InnerCollection.GetValues(header); 
            // If we have no information about the header or it doesn't allow
            // multiple values, just return the values. 
            if (Info == null || Values == null || !Info.AllowMultiValues) { 
                return Values;
            } 
            // Here we have a multi value header. We need to go through
            // each entry in the multi values array, and if an entry itself
            // has multiple values we'll need to combine those in.
            // 
            // We do some optimazation here, where we try not to copy the
            // values unless there really is one that have multiple values. 
            string[] TempValues; 
            ArrayList ValueList = null;
            int i; 
            for (i = 0; i < Values.Length; i++) {
                // Parse this value header.
                TempValues = Info.Parser(Values[i]);
                // If we don't have an array list yet, see if this 
                // value has multiple values.
                if (ValueList == null) { 
                    // See if it has multiple values. 
                    if (TempValues.Length > 1) {
                        // It does, so we need to create an array list that 
                        // represents the Values, then trim out this one and
                        // the ones after it that haven't been parsed yet.
                        ValueList = new ArrayList(Values);
                        ValueList.RemoveRange(i, Values.Length - i); 
                        ValueList.AddRange(TempValues);
                    } 
                } 
                else {
                    // We already have an ArrayList, so just add the values. 
                    ValueList.AddRange(TempValues);
                }
            }
            // See if we have an ArrayList. If we don't, just return the values. 
            // Otherwise convert the ArrayList to a string array and return that.
            if (ValueList != null) { 
                string[] ReturnArray = new string[ValueList.Count]; 
                ValueList.CopyTo(ReturnArray);
                return ReturnArray; 
            }
            return Values;
        }
 

        // ToString()  - 
        // Routine Description: 
        //     Generates a string representation of the headers, that is ready to be sent except for it being in string format:
        //     the format looks like: 
        //
        //     Header-Name: Header-Value\r\n
        //     Header-Name2: Header-Value2\r\n
        //     ... 
        //     Header-NameN: Header-ValueN\r\n
        //     \r\n 
        // 
        //     Uses the string builder class to Append the elements together.
        // Arguments: 
        //     None.
        // Return Value:
        //     string
 
        /// 
        ///  
        ///     
        ///       Obsolete.
        ///     
        /// 
        public override string ToString() {
            string result = GetAsString(this, false, false);
            GlobalLog.Print("WebHeaderCollection::ToString: \r\n" + result); 
            return result;
        } 
 
        internal string ToString(bool forTrace)
        { 
            return GetAsString(this, false, true);
        }

 
        //
        // if winInetCompat = true then it will not insert spaces after ':' 
        // and it will output "~U" header first 
        //
        internal static string GetAsString(NameValueCollection cc, 
                                           bool                winInetCompat,
                                           bool                forTrace) {
#if FEATURE_PAL
            if (winInetCompat) { 
                throw new InvalidOperationException();
            } 
#endif // FEATURE_PAL 

            if (cc == null || cc.Count == 0) { 
                return "\r\n";
            }
            StringBuilder sb = new StringBuilder(ApproxAveHeaderLineSize*cc.Count);
            string statusLine; 
            statusLine = cc[string.Empty];
            if (statusLine != null) { 
                sb.Append(statusLine).Append("\r\n"); 
            }
            for (int i = 0; i < cc.Count ; i++) { 
                string key = cc.GetKey(i) as string;
                string val = cc.Get(i) as string;
                /*
                if (forTrace) 
                {
                    // Put a condition here that if we are using basic auth, 
                    // we shouldn't put the authorization header. Otherwise 
                    // the password will get saved in the trace.
                    if (using basic) 
                        continue;
                }
                */
                if (ValidationHelper.IsBlankString(key)) { 
                    continue;
                } 
                sb.Append(key); 
                if (winInetCompat) {
                    sb.Append(':'); 
                }
                else {
                    sb.Append(": ");
                } 
                sb.Append(val).Append("\r\n");
            } 
            if (!forTrace) 
                sb.Append("\r\n");
            return sb.ToString(); 
        }


        // ToByteArray()  - 
        // Routine Description:
        //     Generates a byte array representation of the headers, that is ready to be sent. 
        //     So it Serializes our headers into a byte array suitable for sending over the net. 
        //
        //     the format looks like: 
        //
        //     Header-Name1: Header-Value1\r\n
        //     Header-Name2: Header-Value2\r\n
        //     ... 
        //     Header-NameN: Header-ValueN\r\n
        //     \r\n 
        // 
        //     Uses the ToString() method to generate, and then performs conversion.
        // 
        //     Performance Note:  Why are we not doing a single copy/covert run?
        //     As the code before used to know the size of the output!
        //     Because according to Demitry, its cheaper to copy the headers twice,
        //     then it is to call the UNICODE to ANSI conversion code many times. 
        // Arguments:
        //     None. 
        // Return Value: 
        //     byte [] - array of bytes values
 
        /// 
        /// 
        ///    
        ///       Obsolete. 
        ///    
        ///  
        public byte[] ToByteArray() { 
            // Make sure the buffer is big enough.
            string tempStr = ToString(); 
            //
            // Use the string of headers, convert to Char Array,
            //  then convert to Bytes,
            //  serializing finally into the buffer, along the way. 
            //
            byte[] buffer = HeaderEncoding.GetBytes(tempStr); 
            return buffer; 
        }
 
        /// 
        ///    Tests if access to the HTTP header with the provided name is accessible for setting.
        /// 
        public static bool IsRestricted(string headerName) 
        {
            return IsRestricted(headerName, false); 
        } 

        public static bool IsRestricted(string headerName, bool response) 
        {
            return response ? HInfo[CheckBadChars(headerName, false)].IsResponseRestricted : HInfo[CheckBadChars(headerName, false)].IsRequestRestricted;
        }
 

        ///  
        ///     
        ///       Initializes a new instance of the 
        ///       class. 
        ///    
        /// 
        public WebHeaderCollection() : base(DBNull.Value)
        { 
        }
 
        internal WebHeaderCollection(WebHeaderCollectionType type) : base(DBNull.Value) 
        {
            m_Type = type; 
            if (type == WebHeaderCollectionType.HttpWebResponse)
                m_CommonHeaders = new string[s_CommonHeaderNames.Length - 1];  // Minus one for the sentinel.
        }
 
        //This is for Cache
        internal WebHeaderCollection(NameValueCollection cc): base(DBNull.Value) 
        { 
            m_InnerCollection = new NameValueCollection(cc.Count + 2, CaseInsensitiveAscii.StaticInstance);
            int len = cc.Count; 
            for (int i = 0; i < len; ++i) {
                String key = cc.GetKey(i);
                String[] values = cc.GetValues(i);
                if (values != null) { 
                    for (int j = 0; j < values.Length; j++) {
                        InnerCollection.Add(key, values[j]); 
                    } 
                }
                else { 
                    InnerCollection.Add(key, null);
                }
            }
        } 

        // 
        // ISerializable constructor 
        //
        ///  
        ///    [To be supplied.]
        /// 
        protected WebHeaderCollection(SerializationInfo serializationInfo, StreamingContext streamingContext) :
            base(DBNull.Value) 
        {
            int count = serializationInfo.GetInt32("Count"); 
            m_InnerCollection = new NameValueCollection(count + 2, CaseInsensitiveAscii.StaticInstance); 
            for (int i = 0; i < count; i++) {
                string headerName = serializationInfo.GetString(i.ToString(NumberFormatInfo.InvariantInfo)); 
                string headerValue = serializationInfo.GetString((i+count).ToString(NumberFormatInfo.InvariantInfo));
                GlobalLog.Print("WebHeaderCollection::.ctor(ISerializable) calling InnerCollection.Add() key:[" + headerName + "], value:[" + headerValue + "]");
                InnerCollection.Add(headerName, headerValue);
            } 
        }
 
        public override void OnDeserialization(object sender) { 
            //
 

        }

        // 
        // ISerializable method
        // 
        ///  
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] 		
        public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) { 
            //
            // for now disregard streamingContext.
            //
            NormalizeCommonHeaders(); 
            serializationInfo.AddValue("Count", Count);
            for (int i = 0; i < Count; i++) 
            { 
                serializationInfo.AddValue(i.ToString(NumberFormatInfo.InvariantInfo), GetKey(i));
                serializationInfo.AddValue((i + Count).ToString(NumberFormatInfo.InvariantInfo), Get(i)); 
            }
        }

 
        // we use this static class as a helper class to encode/decode HTTP headers.
        // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF 
        // and a byte in the range 0x00-0xFF (which is the range that can hit the network). 
        // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow.
        // It doesn't work for string -> byte[] because of best-fit-mapping problems. 
        internal static class HeaderEncoding
        {
            internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount)
            { 
                fixed(byte* pBytes = bytes)
                    return GetString(pBytes + byteIndex, byteCount); 
            } 

            internal static unsafe string GetString(byte* pBytes, int byteCount) 
            {
                if (byteCount < 1)
                    return "";
 
                string s = new String('\0', byteCount);
 
                fixed (char* pStr = s) 
                {
                    char* pString = pStr; 
                    while (byteCount >= 8)
                    {
                        pString[0] = (char) pBytes[0];
                        pString[1] = (char) pBytes[1]; 
                        pString[2] = (char) pBytes[2];
                        pString[3] = (char) pBytes[3]; 
                        pString[4] = (char) pBytes[4]; 
                        pString[5] = (char) pBytes[5];
                        pString[6] = (char) pBytes[6]; 
                        pString[7] = (char) pBytes[7];
                        pString += 8;
                        pBytes += 8;
                        byteCount -= 8; 
                    }
                    for (int i = 0; i < byteCount; i++) 
                    { 
                        pString[i] = (char) pBytes[i];
                    } 
                }

                return s;
            } 

            internal static int GetByteCount(string myString) { 
                return myString.Length; 
            }
            internal unsafe static void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex) { 
                if (myString.Length==0) {
                    return;
                }
                fixed (byte *bufferPointer = bytes) { 
                    byte* newBufferPointer = bufferPointer + byteIndex;
                    int finalIndex = charIndex + charCount; 
                    while (charIndex 
            // TEXT           = 
            // CTL            =  
            // SP             = 
            // HT             = 
            // CR             = 
            // LF             =  
            // LWS            = [CR LF] 1*( SP | HT )
            // CHAR           =  
            // token          = 1* 
            // separators     = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
            // quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> ) 
            // qdtext         = >
            // quoted-pair    = "\" CHAR
            //
 
            //
            // At each iteration of the following loop we expect to parse a single HTTP header entirely. 
            // 
            for (;;) {
                // 
                // trim leading whitespaces (LWS) just for extra robustness, in fact if there are leading white spaces then:
                // 1) it could be that after the status line we might have spaces. handle this.
                // 2) this should have been detected to be a multiline header so there'll be no spaces and we'll spend some time here.
                // 
                headerName = string.Empty;
                headerValue = string.Empty; 
                spaceAfterLf = false; 
                headerMultiLineValue = null;
 
                if (Count == 0) {
                    //
                    // so, restrict this extra trimming only on the first header line
                    // 
                    while (index < size) {
                         ch = (char) byteBuffer[index]; 
                         if (ch == ' ' || ch == '\t') { 
                             ++index;
                            if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                                parseStatus = DataParseStatus.DataTooBig;
                                goto quit;
                            }
                        } 
                        else {
                            break; 
                        } 
                    }
 
                    if (index==size) {
                        //
                        // we reached the end of the buffer. ask for more data.
                        // 
                        parseStatus = DataParseStatus.NeedMoreData;
                        goto quit; 
                    } 
                }
 
                //
                // what we have here is the beginning of a new header
                //
                headerNameStartOffset = index; 

                while (index < size) { 
                    ch = (char) byteBuffer[index]; 
                    if (ch != ':' && ch != '\n') {
                        if (ch > ' ') { 
                            //
                            // if there's an illegal character we should return DataParseStatus.Invalid
                            // instead we choose to be flexible, try to trim it, but include it in the string
                            // 
                            headerNameEndOffset = index;
                        } 
                        ++index; 
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig; 
                            goto quit;
                        }
                    }
                    else { 
                        if (ch == ':') {
                            ++index; 
                            if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                                parseStatus = DataParseStatus.DataTooBig;
                                goto quit; 
                            }
                        }
                        break;
                    } 
                }
                if (index==size) { 
                    // 
                    // we reached the end of the buffer. ask for more data.
                    // 
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }
 
startOfValue:
                // 
                // skip all [' ','\t','\r','\n'] characters until HeaderValue starts 
                // if we didn't find any headers yet, we set numberOfLf to 1
                // so that we take the '\n' from the status line into account 
                //

                numberOfLf = (Count == 0 && headerNameEndOffset < 0) ? 1 : 0;
                while (index=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit; 
                        }
                    }
                    else {
                        break; 
                    }
                } 
                if (numberOfLf==2 || (numberOfLf==1 && !spaceAfterLf)) { 
                    //
                    // if we've counted two '\n' we got at the end of the headers even if we're past the end of the buffer 
                    // if we've counted one '\n' and the first character after that was a ' ' or a '\t'
                    // no matter if we found a ':' or not, treat this as an empty header name.
                    //
                    goto addHeader; 
                }
                if (index==size) { 
                    // 
                    // we reached the end of the buffer. ask for more data.
                    // 
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }
 
                headerValueStartOffset = index;
 
                while (index ' ') {
                            headerValueEndOffset = index;
                        }
                        ++index; 
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig; 
                            goto quit; 
                        }
                    } 
                    else {
                        break;
                    }
                } 
                if (index==size) {
                    // 
                    // we reached the end of the buffer. ask for more data. 
                    //
                    parseStatus = DataParseStatus.NeedMoreData; 
                    goto quit;
                }

                // 
                // at this point we found either a '\n' or the end of the headers
                // hence we are at the end of the Header Line. 4 options: 
                // 1) need more data 
                // 2) if we find two '\n' => end of headers
                // 3) if we find one '\n' and a ' ' or a '\t' => multiline header 
                // 4) if we find one '\n' and a valid char => next header
                //
                numberOfLf = 0;
                while (index=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit; 
                        }
                    } 
                    else { 
                        break;
                    } 
                }
                if (index==size && numberOfLf<2) {
                    //
                    // we reached the end of the buffer but not of the headers. ask for more data. 
                    //
                    parseStatus = DataParseStatus.NeedMoreData; 
                    goto quit; 
                }
 
addHeader:
                if (headerValueStartOffset>=0 && headerValueStartOffset>headerNameEndOffset && headerValueEndOffset>=headerValueStartOffset) {
                    //
                    // Encoding fastest way to build the UNICODE string off the byte[] 
                    //
                    headerValue = HeaderEncoding.GetString(byteBuffer + headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1); 
                } 

                // 
                // if we got here from the beginning of the for loop, headerMultiLineValue will be null
                // otherwise it will contain the headerValue constructed for the multiline header
                // add this line as well to it, separated by a single space
                // 
                headerMultiLineValue = (headerMultiLineValue==null ? headerValue : headerMultiLineValue + " " + headerValue);
 
                if (index < size && numberOfLf == 1) { 
                    ch = (char) byteBuffer[index];
                    if (ch == ' ' || ch == '\t') { 
                        //
                        // since we found only one Lf and the next header line begins with a Lws,
                        // this is the beginning of a multiline header.
                        // parse the next line into headerValue later it will be added to headerMultiLineValue 
                        //
                        ++index; 
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit; 
                        }
                        goto startOfValue;
                    }
                } 

                if (headerNameStartOffset>=0 && headerNameEndOffset>=headerNameStartOffset) { 
                    // 
                    // Encoding is the fastest way to build the UNICODE string off the byte[]
                    // 
                    headerName = HeaderEncoding.GetString(byteBuffer + headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1);
                }

                // 
                // now it's finally safe to add the header if we have a name for it
                // 
                if (headerName.Length>0) { 
                    //
                    // the base clasee will check for pre-existing headerValue and append 
                    // it using commas as indicated in the RFC
                    //
                    GlobalLog.Print("WebHeaderCollection::ParseHeaders() calling AddInternal() key:[" + headerName + "], value:[" + headerMultiLineValue + "]");
                    AddInternal(headerName, headerMultiLineValue); 
                }
 
                // 
                // and update unparsed
                // 
                totalResponseHeadersLength = localTotalResponseHeadersLength;
                unparsed = index;

                if (numberOfLf==2) { 
                    parseStatus = DataParseStatus.Done;
                    goto quit; 
                } 

            } // for (;;) 

quit:
            GlobalLog.Leave("WebHeaderCollection::ParseHeaders() returning parseStatus:" + parseStatus.ToString());
            if (parseStatus == DataParseStatus.Invalid) { 
                parseError.Section = WebParseErrorSection.ResponseHeader;
                parseError.Code    = parseErrorCode; 
            } 

            return parseStatus; 
            }
        }

        // 
        // Alternative parsing that follows RFC2616.  Like the above, this trims both sides of the header value and replaces
        // folding with a single space. 
        // 
        private enum RfcChar : byte
        { 
            High = 0,
            Reg,
            Ctl,
            CR, 
            LF,
            WS, 
            Colon, 
            Delim
        } 

        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,    RfcChar.LF,    RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.CR,    RfcChar.Ctl,   RfcChar.Ctl,
            RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl, 
            RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl, 
            RfcChar.WS,    RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Delim, RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Colon, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim,
            RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Ctl,
        };

        internal unsafe DataParseStatus ParseHeadersStrict( 
                byte[] buffer,
                int size, 
                ref int unparsed, 
                ref int totalResponseHeadersLength,
                int maximumResponseHeadersLength, 
                ref WebParseError parseError)
        {
            GlobalLog.Enter("WebHeaderCollection::ParseHeadersStrict(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size-unparsed)) + "]");
 
            WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic;
            DataParseStatus parseStatus = DataParseStatus.Invalid; 
 
            int i = unparsed;
            RfcChar ch; 
            int effectiveSize = maximumResponseHeadersLength <= 0 ? Int32.MaxValue : maximumResponseHeadersLength - totalResponseHeadersLength + i;
            DataParseStatus sizeError = DataParseStatus.DataTooBig;
            if (size < effectiveSize)
            { 
                effectiveSize = size;
                sizeError = DataParseStatus.NeedMoreData; 
            } 

            // Verify the size. 
            if (i >= effectiveSize)
            {
                parseStatus = sizeError;
                goto quit; 
            }
 
            fixed (byte* byteBuffer = buffer) 
            {
                while (true) 
                {
                    // If this is CRLF, actually we're done.
                    if (byteBuffer[i] == '\r')
                    { 
                        if (++i == effectiveSize)
                        { 
                            parseStatus = sizeError; 
                            goto quit;
                        } 

                        if (byteBuffer[i++] == '\n')
                        {
                            totalResponseHeadersLength += i - unparsed; 
                            unparsed = i;
                            parseStatus = DataParseStatus.Done; 
                            goto quit; 
                        }
 
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit;
                    } 

                    // Find the header name; only regular characters allowed. 
                    int iBeginName = i; 
                    for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.Reg; i++);
                    if (i == effectiveSize) 
                    {
                        parseStatus = sizeError;
                        goto quit;
                    } 
                    if (i == iBeginName)
                    { 
                        parseStatus = DataParseStatus.Invalid; 
                        parseErrorCode = WebParseErrorCode.InvalidHeaderName;
                        goto quit; 
                    }

                    // Read to a colon.
                    int iEndName = i - 1; 
                    int crlf = 0;  // 1 = cr, 2 = crlf
                    for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) != RfcChar.Colon; i++) 
                    { 
                        switch (ch)
                        { 
                            case RfcChar.WS:
                                if (crlf == 1)
                                {
                                    break; 
                                }
                                crlf = 0; 
                                continue; 

                            case RfcChar.CR: 
                                if (crlf == 0)
                                {
                                    crlf = 1;
                                    continue; 
                                }
                                break; 
 
                            case RfcChar.LF:
                                if (crlf == 1) 
                                {
                                    crlf = 2;
                                    continue;
                                } 
                                break;
                        } 
                        parseStatus = DataParseStatus.Invalid; 
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit; 
                    }
                    if (i == effectiveSize)
                    {
                        parseStatus = sizeError; 
                        goto quit;
                    } 
                    if (crlf != 0) 
                    {
                        parseStatus = DataParseStatus.Invalid; 
                        parseErrorCode = WebParseErrorCode.IncompleteHeaderLine;
                        goto quit;
                    }
 
                    // Skip the colon.
                    if (++i == effectiveSize) 
                    { 
                        parseStatus = sizeError;
                        goto quit; 
                    }

                    // Read the value.  crlf = 3 means in the whitespace after a CRLF
                    int iBeginValue = -1; 
                    int iEndValue = -1;
                    StringBuilder valueAccumulator = null; 
                    for (; i < effectiveSize && ((ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.WS || crlf != 2); i++) 
                    {
                        switch (ch) 
                        {
                            case RfcChar.WS:
                                if (crlf == 1)
                                { 
                                    break;
                                } 
                                if (crlf == 2) 
                                {
                                    crlf = 3; 
                                }
                                continue;

                            case RfcChar.CR: 
                                if (crlf == 0)
                                { 
                                    crlf = 1; 
                                    continue;
                                } 
                                break;

                            case RfcChar.LF:
                                if (crlf == 1) 
                                {
                                    crlf = 2; 
                                    continue; 
                                }
                                break; 

                            case RfcChar.High:
                            case RfcChar.Colon:
                            case RfcChar.Delim: 
                            case RfcChar.Reg:
                                if (crlf == 1) 
                                { 
                                    break;
                                } 
                                if (crlf == 3)
                                {
                                    crlf = 0;
                                    if (iBeginValue != -1) 
                                    {
                                        string s = HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1); 
                                        if (valueAccumulator == null) 
                                        {
                                            valueAccumulator = new StringBuilder(s, s.Length * 5); 
                                        }
                                        else
                                        {
                                            valueAccumulator.Append(" "); 
                                            valueAccumulator.Append(s);
                                        } 
                                    } 
                                    iBeginValue = -1;
                                } 
                                if (iBeginValue == -1)
                                {
                                    iBeginValue = i;
                                } 
                                iEndValue = i;
                                continue; 
                        } 
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError; 
                        goto quit;
                    }
                    if (i == effectiveSize)
                    { 
                        parseStatus = sizeError;
                        goto quit; 
                    } 

                    // Make the value. 
                    string sValue = iBeginValue == -1 ? "" : HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1);
                    if (valueAccumulator != null)
                    {
                        if (sValue.Length != 0) 
                        {
                            valueAccumulator.Append(" "); 
                            valueAccumulator.Append(sValue); 
                        }
                        sValue = valueAccumulator.ToString(); 
                    }

                    // Make the name.  See if it's a common header first.
                    string sName = null; 
                    int headerNameLength = iEndName - iBeginName + 1;
                    if (m_CommonHeaders != null) 
                    { 
                        int iHeader = s_CommonHeaderHints[byteBuffer[iBeginName] & 0x1f];
                        if (iHeader >= 0) 
                        {
                            while (true)
                            {
                                string s = s_CommonHeaderNames[iHeader++]; 

                                // Not found if we get to a shorter header or one with a different first character. 
                                if (s.Length < headerNameLength || CaseInsensitiveAscii.AsciiToLower[byteBuffer[iBeginName]] != CaseInsensitiveAscii.AsciiToLower[s[0]]) 
                                    break;
 
                                // Keep looking if the common header is too long.
                                if (s.Length > headerNameLength)
                                    continue;
 
                                int j;
                                byte* pBuffer = byteBuffer + iBeginName + 1; 
                                for (j = 1; j < s.Length; j++) 
                                {
                                    // Avoid the case-insensitive compare in the common case where they match. 
                                    if (*(pBuffer++) != s[j] && CaseInsensitiveAscii.AsciiToLower[*(pBuffer - 1)] != CaseInsensitiveAscii.AsciiToLower[s[j]])
                                        break;
                                }
                                if (j == s.Length) 
                                {
                                    // Set it to the appropriate index. 
                                    m_NumCommonHeaders++; 
                                    iHeader--;
                                    if (m_CommonHeaders[iHeader] == null) 
                                    {
                                        m_CommonHeaders[iHeader] = sValue;
                                    }
                                    else 
                                    {
                                        // Don't currently handle combining multiple header instances in the common header case. 
                                        // Nothing to do but punt them all to the NameValueCollection. 
                                        NormalizeCommonHeaders();
                                        AddInternalNotCommon(s, sValue); 
                                    }

                                    sName = s;
                                    break; 
                                }
                            } 
                        } 
                    }
 
                    // If it wasn't a common header, add it to the hash.
                    if (sName == null)
                    {
                        sName = HeaderEncoding.GetString(byteBuffer + iBeginName, headerNameLength); 
                        AddInternalNotCommon(sName, sValue);
                    } 
 
                    totalResponseHeadersLength += i - unparsed;
                    unparsed = i; 
                }
            }

quit: 
            GlobalLog.Leave("WebHeaderCollection::ParseHeadersStrict() returning parseStatus:" + parseStatus.ToString());
 
            if (parseStatus == DataParseStatus.Invalid) { 
                parseError.Section = WebParseErrorSection.ResponseHeader;
                parseError.Code    = parseErrorCode; 
            }

            return parseStatus;
        } 

        // 
        // Keeping this version for backwards compatibility (mostly with reflection).  Remove some day, along with the interface 
        // explicit reimplementation.
        // 
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)]
        void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        { 
            GetObjectData(serializationInfo, streamingContext);
        } 
 
        // Override Get() to check the common headers.
        public override string Get(string name) 
        {
            // In this case, need to make sure name doesn't have any Unicode since it's being used as an index into tables.
            if (m_CommonHeaders != null && name != null && name.Length > 0 && name[0] < 256)
            { 
                int iHeader = s_CommonHeaderHints[name[0] & 0x1f];
                if (iHeader >= 0) 
                { 
                    while (true)
                    { 
                        string s = s_CommonHeaderNames[iHeader++];

                        // Not found if we get to a shorter header or one with a different first character.
                        if (s.Length < name.Length || CaseInsensitiveAscii.AsciiToLower[name[0]] != CaseInsensitiveAscii.AsciiToLower[s[0]]) 
                            break;
 
                        // Keep looking if the common header is too long. 
                        if (s.Length > name.Length)
                            continue; 

                        int j;
                        for (j = 1; j < s.Length; j++)
                        { 
                            // Avoid the case-insensitive compare in the common case where they match.
                            if (name[j] != s[j] && (name[j] > 255 || CaseInsensitiveAscii.AsciiToLower[name[j]] != CaseInsensitiveAscii.AsciiToLower[s[j]])) 
                                break; 
                        }
                        if (j == s.Length) 
                        {
                            // Get the appropriate header.
                            return m_CommonHeaders[iHeader - 1];
                        } 
                    }
                } 
            } 

            // Fall back to normal lookup. 
            if (m_InnerCollection == null)
                return null;
            return m_InnerCollection.Get(name);
        } 

 
        // 
        // Additional overrides required to fully orphan the base implementation.
        // 
        public override IEnumerator GetEnumerator()
        {
            NormalizeCommonHeaders();
            return new NameObjectKeysEnumerator(InnerCollection); 
        }
 
        public override int Count 
        {
            get 
            {
                return (m_InnerCollection == null ? 0 : m_InnerCollection.Count) + m_NumCommonHeaders;
            }
        } 

        public override KeysCollection Keys 
        { 
            get
            { 
                NormalizeCommonHeaders();
                return InnerCollection.Keys;
            }
        } 

        internal override bool InternalHasKeys() 
        { 
            NormalizeCommonHeaders();
            if (m_InnerCollection == null) 
                return false;
            return m_InnerCollection.HasKeys();
        }
 
        public override string Get(int index)
        { 
            NormalizeCommonHeaders(); 
            return InnerCollection.Get(index);
        } 

        public override string[] GetValues(int index)
        {
            NormalizeCommonHeaders(); 
            return InnerCollection.GetValues(index);
        } 
 
        public override string GetKey(int index)
        { 
            NormalizeCommonHeaders();
            return InnerCollection.GetKey(index);
        }
 
        public override string[] AllKeys
        { 
            get 
            {
                NormalizeCommonHeaders(); 
                return InnerCollection.AllKeys;
            }
        }
 
        public override void Clear()
        { 
            m_CommonHeaders = null; 
            m_NumCommonHeaders = 0;
            InvalidateCachedArrays(); 
            if (m_InnerCollection != null)
                m_InnerCollection.Clear();
        }
    } // class WebHeaderCollection 

 
    internal class CaseInsensitiveAscii : IEqualityComparer, IComparer{ 
        // ASCII char ToLower table
        internal static readonly CaseInsensitiveAscii StaticInstance = new CaseInsensitiveAscii(); 
        internal static readonly byte[] AsciiToLower = new byte[] {
              0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
             10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
             20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 
             30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
             40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 
             50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 
             60, 61, 62, 63, 64, 97, 98, 99,100,101, //  60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
            102,103,104,105,106,107,108,109,110,111, //  70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 
            112,113,114,115,116,117,118,119,120,121, //  80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
            122, 91, 92, 93, 94, 95, 96, 97, 98, 99, //  90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
            100,101,102,103,104,105,106,107,108,109,
            110,111,112,113,114,115,116,117,118,119, 
            120,121,122,123,124,125,126,127,128,129,
            130,131,132,133,134,135,136,137,138,139, 
            140,141,142,143,144,145,146,147,148,149, 
            150,151,152,153,154,155,156,157,158,159,
            160,161,162,163,164,165,166,167,168,169, 
            170,171,172,173,174,175,176,177,178,179,
            180,181,182,183,184,185,186,187,188,189,
            190,191,192,193,194,195,196,197,198,199,
            200,201,202,203,204,205,206,207,208,209, 
            210,211,212,213,214,215,216,217,218,219,
            220,221,222,223,224,225,226,227,228,229, 
            230,231,232,233,234,235,236,237,238,239, 
            240,241,242,243,244,245,246,247,248,249,
            250,251,252,253,254,255 
        };

        // ASCII string case insensitive hash function
        public int GetHashCode(object myObject) { 
            string myString = myObject as string;
            if (myObject == null) { 
                return 0; 
            }
            int myHashCode = myString.Length; 
            if (myHashCode == 0) {
                return 0;
            }
            myHashCode ^= AsciiToLower[(byte)myString[0]]<<24 ^ AsciiToLower[(byte)myString[myHashCode-1]]<<16; 
            return myHashCode;
        } 
 
        // ASCII string case insensitive comparer
        public int Compare(object firstObject, object secondObject) { 
            string firstString = firstObject as string;
            string secondString = secondObject as string;
            if (firstString==null) {
                return secondString == null ? 0 : -1; 
            }
            if (secondString == null) { 
                return 1; 
            }
            int result = firstString.Length - secondString.Length; 
            int comparisons = result > 0 ? secondString.Length : firstString.Length;
            int difference, index = 0;
            while ( index < comparisons ) {
                difference = (int)(AsciiToLower[ firstString[index] ] - AsciiToLower[ secondString[index] ]); 
                if ( difference != 0 ) {
                    result = difference; 
                    break; 
                }
                index++; 
            }
            return result;
        }
 
        // ASCII string case insensitive hash function
        int FastGetHashCode(string myString) { 
            int myHashCode = myString.Length; 
            if (myHashCode!=0) {
                myHashCode ^= AsciiToLower[(byte)myString[0]]<<24 ^ AsciiToLower[(byte)myString[myHashCode-1]]<<16; 
            }
            return myHashCode;
        }
 
        // ASCII string case insensitive comparer
        public new bool Equals(object firstObject, object secondObject) { 
            string firstString = firstObject as string; 
            string secondString = secondObject as string;
            if (firstString==null) { 
                return secondString==null;
            }
            if (secondString!=null) {
                int index = firstString.Length; 
                if (index==secondString.Length) {
                    if (FastGetHashCode(firstString)==FastGetHashCode(secondString)) { 
                        int comparisons = firstString.Length; 
                        while (index>0) {
                            index--; 
                            if (AsciiToLower[firstString[index]]!=AsciiToLower[secondString[index]]) {
                                return false;
                            }
                        } 
                        return true;
                    } 
                } 
            }
            return false; 
        }
    }

    internal class HostHeaderString { 

        private bool m_Converted; 
        private string m_String; 
        private byte[] m_Bytes;
 
        internal HostHeaderString() {
            Init(null);
        }
 
        internal HostHeaderString(string s) {
            Init(s); 
        } 

        private void Init(string s) { 
            m_String = s;
            m_Converted = false;
            m_Bytes = null;
        } 

        private void Convert() { 
            if (m_String != null && !m_Converted) { 
                m_Bytes = Encoding.Default.GetBytes(m_String);
                string copy = Encoding.Default.GetString(m_Bytes); 
                if (!(string.Compare(m_String, copy, StringComparison.Ordinal) == 0)) {
                    m_Bytes = Encoding.UTF8.GetBytes(m_String);
                }
            } 
        }
 
        internal string String { 
            get { return m_String; }
            set { 
                Init(value);
            }
        }
 
        internal int ByteCount {
            get { 
                Convert(); 
                return m_Bytes.Length;
            } 
        }

        internal byte[] Bytes {
            get { 
                Convert();
                return m_Bytes; 
            } 
        }
 
        internal void Copy(byte[] destBytes, int destByteIndex) {
            Convert();
            Array.Copy(m_Bytes, 0, destBytes, destByteIndex, m_Bytes.Length);
        } 

    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net { 
    using System.Net.Cache; 
    using System.Collections;
    using System.Collections.Specialized; 
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Globalization; 
    using System.Security.Permissions;
 
    internal enum WebHeaderCollectionType : ushort { 
        Unknown,
        WebRequest, 
        WebResponse,
        HttpWebRequest,
        HttpWebResponse,
        HttpListenerRequest, 
        HttpListenerResponse,
        FtpWebRequest, 
        FtpWebResponse, 
        FileWebRequest,
        FileWebResponse, 
    }

    //
    // HttpHeaders - this is our main HttpHeaders object, 
    //  which is a simple collection of name-value pairs,
    //  along with additional methods that provide HTTP parsing 
    //  collection to sendable buffer capablities and other enhansments 
    //  We also provide validation of what headers are allowed to be added.
    // 

    /// 
    ///    
    ///       Contains protocol headers associated with a 
    ///       request or response.
    ///     
    ///  
    [ComVisible(true), Serializable]
    public class WebHeaderCollection : NameValueCollection, ISerializable { 
        //
        // Data and Constants
        //
        private const int ApproxAveHeaderLineSize = 30; 
        private const int ApproxHighAvgNumHeaders = 16;
        private static readonly HeaderInfoTable HInfo = new HeaderInfoTable(); 
 
        //
        // Common Headers - used only when receiving a response, and internally.  If the user ever requests a header, 
        // all the common headers are moved into the hashtable.
        //
        private string[] m_CommonHeaders;
        private int m_NumCommonHeaders; 

        // Grouped by first character, so lookup is faster.  The table s_CommonHeaderHints maps first letters to indexes in this array. 
        // After first character, sort by decreasing length.  It's ok if two headers have the same first character and length. 
        private static readonly string[] s_CommonHeaderNames = new string[] {
            HttpKnownHeaderNames.AcceptRanges,      // "Accept-Ranges"       13 
            HttpKnownHeaderNames.ContentLength,     // "Content-Length"      14
            HttpKnownHeaderNames.CacheControl,      // "Cache-Control"       13
            HttpKnownHeaderNames.ContentType,       // "Content-Type"        12
            HttpKnownHeaderNames.Date,              // "Date"                 4 
            HttpKnownHeaderNames.Expires,           // "Expires"              7
            HttpKnownHeaderNames.ETag,              // "ETag"                 4 
            HttpKnownHeaderNames.LastModified,      // "Last-Modified"       13 
            HttpKnownHeaderNames.Location,          // "Location"             8
            HttpKnownHeaderNames.ProxyAuthenticate, // "Proxy-Authenticate"  18 
            HttpKnownHeaderNames.P3P,               // "P3P"                  3
            HttpKnownHeaderNames.SetCookie2,        // "Set-Cookie2"         11
            HttpKnownHeaderNames.SetCookie,         // "Set-Cookie"          10
            HttpKnownHeaderNames.Server,            // "Server"               6 
            HttpKnownHeaderNames.Via,               // "Via"                  3
            HttpKnownHeaderNames.WWWAuthenticate,   // "WWW-Authenticate"    16 
            HttpKnownHeaderNames.XAspNetVersion,    // "X-AspNet-Version"    16 
            HttpKnownHeaderNames.XPoweredBy,        // "X-Powered-By"        12
            "[" };  // This sentinel will never match.  (This character isn't in the hint table.) 

        // Mask off all but the bottom five bits, and look up in this array.
        private static readonly sbyte[] s_CommonHeaderHints = new sbyte[] {
            -1,  0, -1,  1,  4,  5, -1, -1,   // - a b c d e f g 
            -1, -1, -1, -1,  7, -1, -1, -1,   // h i j k l m n o
             9, -1, -1, 11, -1, -1, 14, 15,   // p q r s t u v w 
            16, -1, -1, -1, -1, -1, -1, -1 }; // x y z [ - - - - 

        private const int c_AcceptRanges      =  0; 
        private const int c_ContentLength     =  1;
        private const int c_CacheControl      =  2;
        private const int c_ContentType       =  3;
        private const int c_Date              =  4; 
        private const int c_Expires           =  5;
        private const int c_ETag              =  6; 
        private const int c_LastModified      =  7; 
        private const int c_Location          =  8;
        private const int c_ProxyAuthenticate =  9; 
        private const int c_P3P               = 10;
        private const int c_SetCookie2        = 11;
        private const int c_SetCookie         = 12;
        private const int c_Server            = 13; 
        private const int c_Via               = 14;
        private const int c_WwwAuthenticate   = 15; 
        private const int c_XAspNetVersion    = 16; 
        private const int c_XPoweredBy        = 17;
 
        // Easy fast lookups for common headers.  More can be added.
        internal string ContentLength
        {
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_ContentLength] : Get(s_CommonHeaderNames[c_ContentLength]); 
            } 
        }
 
        internal string CacheControl
        {
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_CacheControl] : Get(s_CommonHeaderNames[c_CacheControl]);
            } 
        } 

        internal string ContentType 
        {
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_ContentType] : Get(s_CommonHeaderNames[c_ContentType]); 
            }
        } 
 
        internal string Date
        { 
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Date] : Get(s_CommonHeaderNames[c_Date]);
            } 
        }
 
        internal string Expires 
        {
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Expires] : Get(s_CommonHeaderNames[c_Expires]);
            }
        } 

        internal string ETag 
        { 
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_ETag] : Get(s_CommonHeaderNames[c_ETag]);
            }
        }
 
        internal string LastModified
        { 
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_LastModified] : Get(s_CommonHeaderNames[c_LastModified]); 
            }
        }

        internal string Location 
        {
            get 
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_Location] : Get(s_CommonHeaderNames[c_Location]);
            } 
        }

        internal string ProxyAuthenticate
        { 
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_ProxyAuthenticate] : Get(s_CommonHeaderNames[c_ProxyAuthenticate]); 
            }
        } 

        internal string SetCookie2
        {
            get 
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_SetCookie2] : Get(s_CommonHeaderNames[c_SetCookie2]); 
            } 
        }
 
        internal string SetCookie
        {
            get
            { 
                return m_CommonHeaders != null ? m_CommonHeaders[c_SetCookie] : Get(s_CommonHeaderNames[c_SetCookie]);
            } 
        } 

        internal string Server 
        {
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Server] : Get(s_CommonHeaderNames[c_Server]); 
            }
        } 
 
        internal string Via
        { 
            get
            {
                return m_CommonHeaders != null ? m_CommonHeaders[c_Via] : Get(s_CommonHeaderNames[c_Via]);
            } 
        }
 
        private void NormalizeCommonHeaders() 
        {
            if (m_CommonHeaders == null) 
                return;
            for (int i = 0; i < m_CommonHeaders.Length; i++)
                if (m_CommonHeaders[i] != null)
                    InnerCollection.Add(s_CommonHeaderNames[i], m_CommonHeaders[i]); 

            m_CommonHeaders = null; 
            m_NumCommonHeaders = 0; 
        }
 
        //
        // To ensure C++ and IL callers can't pollute the underlying collection by calling overridden base members directly, we
        // will use a member collection instead.
        private NameValueCollection m_InnerCollection; 

        private NameValueCollection InnerCollection 
        { 
            get
            { 
                if (m_InnerCollection == null)
                    m_InnerCollection = new NameValueCollection(ApproxHighAvgNumHeaders, CaseInsensitiveAscii.StaticInstance);
                return m_InnerCollection;
            } 
        }
 
        // this is the object that created the header collection. 
        private WebHeaderCollectionType m_Type;
 
#if !FEATURE_PAL
        private bool AllowHttpRequestHeader {
            get {
                if (m_Type==WebHeaderCollectionType.Unknown) { 
                    m_Type = WebHeaderCollectionType.WebRequest;
                } 
                return m_Type==WebHeaderCollectionType.WebRequest || m_Type==WebHeaderCollectionType.HttpWebRequest || m_Type==WebHeaderCollectionType.HttpListenerRequest; 
            }
        } 

        internal bool AllowHttpResponseHeader {
            get {
                if (m_Type==WebHeaderCollectionType.Unknown) { 
                    m_Type = WebHeaderCollectionType.WebResponse;
                } 
                return m_Type==WebHeaderCollectionType.WebResponse || m_Type==WebHeaderCollectionType.HttpWebResponse || m_Type==WebHeaderCollectionType.HttpListenerResponse; 
            }
        } 

        public string this[HttpRequestHeader header] {
            get {
                if (!AllowHttpRequestHeader) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
                } 
                return this[UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header)]; 
            }
            set { 
                if (!AllowHttpRequestHeader) {
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
                }
                this[UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header)] = value; 
            }
        } 
        public string this[HttpResponseHeader header] { 
            get {
                if (!AllowHttpResponseHeader) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
                }

                // Some of these can be mapped to Common Headers.  Other cases can be added as needed for perf. 
                if (m_CommonHeaders != null)
                { 
                    switch (header) 
                    {
                        case HttpResponseHeader.ProxyAuthenticate: 
                            return m_CommonHeaders[c_ProxyAuthenticate];

                        case HttpResponseHeader.WwwAuthenticate:
                            return m_CommonHeaders[c_WwwAuthenticate]; 
                    }
                } 
 
                return this[UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header)];
            } 
            set {
                if (!AllowHttpResponseHeader) {
                    throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
                } 
                if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                    if (value!=null && value.Length>ushort.MaxValue) { 
                        throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                    }
                } 
                this[UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header)] = value;
            }
        }
 
        public void Add(HttpRequestHeader header, string value) {
            if (!AllowHttpRequestHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_req)); 
            }
            this.Add(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header), value); 
        }

        public void Add(HttpResponseHeader header, string value) {
            if (!AllowHttpResponseHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
            } 
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                }
            }
            this.Add(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header), value);
        } 

        public void Set(HttpRequestHeader header, string value) { 
            if (!AllowHttpRequestHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
            } 
            this.Set(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header), value);
        }

        public void Set(HttpResponseHeader header, string value) { 
            if (!AllowHttpResponseHeader) {
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp)); 
            } 
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                }
            }
            this.Set(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header), value); 
        }
 
 
        internal void SetInternal(HttpResponseHeader header, string value) {
            if (!AllowHttpResponseHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
            }
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                } 
            } 
            this.SetInternal(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header), value);
        } 


        public void Remove(HttpRequestHeader header) {
            if (!AllowHttpRequestHeader) { 
                throw new InvalidOperationException(SR.GetString(SR.net_headers_req));
            } 
            this.Remove(UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_HEADER_ID.ToString((int)header)); 
        }
 
        public void Remove(HttpResponseHeader header) {
            if (!AllowHttpResponseHeader) {
                throw new InvalidOperationException(SR.GetString(SR.net_headers_rsp));
            } 
            this.Remove(UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_HEADER_ID.ToString((int)header));
        } 
#endif // !FEATURE_PAL 

        // In general, HttpWebResponse headers aren't modified, so these methods don't support common headers. 

        /// 
        ///    [To be supplied.]
        ///  
        protected void AddWithoutValidate(string headerName, string headerValue) {
            headerName = CheckBadChars(headerName, false); 
            headerValue = CheckBadChars(headerValue, true); 
            GlobalLog.Print("WebHeaderCollection::AddWithoutValidate() calling InnerCollection.Add() key:[" + headerName + "], value:[" + headerValue + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (headerValue!=null && headerValue.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                }
            } 
            NormalizeCommonHeaders();
            InvalidateCachedArrays(); 
            InnerCollection.Add(headerName, headerValue); 
        }
 
        internal void SetAddVerified(string name, string value) {
            if(HInfo[name].AllowMultiValues) {
                GlobalLog.Print("WebHeaderCollection::SetAddVerified() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
                NormalizeCommonHeaders(); 
                InvalidateCachedArrays();
                InnerCollection.Add(name, value); 
            } 
            else {
                GlobalLog.Print("WebHeaderCollection::SetAddVerified() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]"); 
                NormalizeCommonHeaders();
                InvalidateCachedArrays();
                InnerCollection.Set(name, value);
            } 
        }
 
        // Below three methods are for fast headers manipulation, bypassing all the checks 
        internal void AddInternal(string name, string value) {
            GlobalLog.Print("WebHeaderCollection::AddInternal() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]"); 
            NormalizeCommonHeaders();
            InvalidateCachedArrays();
            InnerCollection.Add(name, value);
        } 

        internal void ChangeInternal(string name, string value) { 
            GlobalLog.Print("WebHeaderCollection::ChangeInternal() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]"); 
            NormalizeCommonHeaders();
            InvalidateCachedArrays(); 
            InnerCollection.Set(name, value);
        }

 
        internal void RemoveInternal(string name) {
            GlobalLog.Print("WebHeaderCollection::RemoveInternal() calling InnerCollection.Remove() key:[" + name + "]"); 
            NormalizeCommonHeaders(); 
            if (m_InnerCollection != null)
            { 
                InvalidateCachedArrays();
                m_InnerCollection.Remove(name);
            }
        } 

        internal void CheckUpdate(string name, string value) { 
            value = CheckBadChars(value, true); 
            ChangeInternal(name, value);
        } 

        // 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.
        private void AddInternalNotCommon(string name, string value)
        { 
            GlobalLog.Print("WebHeaderCollection::AddInternalNotCommon() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
            InvalidateCachedArrays(); 
            InnerCollection.Add(name, value); 
        }
 

        private static readonly char[] HttpTrimCharacters = new char[]{(char)0x09,(char)0xA,(char)0xB,(char)0xC,(char)0xD,(char)0x20};

        // 
        // CheckBadChars - throws on invalid chars to be not found in header name/value
        // 
        internal static string CheckBadChars(string name, bool isHeaderValue) { 

            if (name == null || name.Length == 0) { 
                // emtpy name is invlaid
                if (!isHeaderValue) {
                    throw name == null ? new ArgumentNullException("name") :
                        new ArgumentException(SR.GetString(SR.net_emptystringcall, "name"), "name"); 
                }
                //empty value is OK 
                return string.Empty; 
            }
 
            if (isHeaderValue) {
                // VALUE check
                //Trim spaces from both ends
                name = name.Trim(HttpTrimCharacters); 

                //First, check for correctly formed multi-line value 
                //Second, check for absenece of CTL characters 
                int crlf = 0;
                for(int i = 0; i < name.Length; ++i) { 
                    char c = (char) (0x000000ff & (uint) name[i]);
                    switch (crlf)
                    {
                        case 0: 
                            if (c == '\r')
                            { 
                                crlf = 1; 
                            }
                            else if (c == '\n') 
                            {
                                // Technically this is bad HTTP.  But it would be a breaking change to throw here.
                                // Is there an exploit?
                                crlf = 2; 
                            }
                            else if (c == 127 || (c < ' ' && c != '\t')) 
                            { 
                                throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidControlChars), "value");
                            } 
                            break;

                        case 1:
                            if (c == '\n') 
                            {
                                crlf = 2; 
                                break; 
                            }
                            throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value"); 

                        case 2:
                            if (c == ' ' || c == '\t')
                            { 
                                crlf = 0;
                                break; 
                            } 
                            throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value");
                    } 
                }
                if (crlf != 0)
                {
                    throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidCRLFChars), "value"); 
                }
            } 
            else { 
                // NAME check
                //First, check for absence of separators and spaces 
                if (name.IndexOfAny(ValidationHelper.InvalidParamChars) != -1) {
                    throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidHeaderChars), "name");
                }
 
                //Second, check for non CTL ASCII-7 characters (32-126)
                if (ContainsNonAsciiChars(name)) { 
                    throw new ArgumentException(SR.GetString(SR.net_WebHeaderInvalidNonAsciiChars), "name"); 
                }
            } 
            return name;
        }

        internal static bool IsValidToken(string token) { 
            return (token.Length > 0)
                && (token.IndexOfAny(ValidationHelper.InvalidParamChars) == -1) 
                && !ContainsNonAsciiChars(token); 
        }
 
        internal static bool ContainsNonAsciiChars(string token) {
            for (int i = 0; i < token.Length; ++i) {
                if ((token[i] < 0x20) || (token[i] > 0x7e)) {
                    return true; 
                }
            } 
            return false; 
        }
 
        //
        // ThrowOnRestrictedHeader - generates an error if the user,
        //  passed in a reserved string as the header name
        // 
        internal void ThrowOnRestrictedHeader(string headerName)
        { 
            if (m_Type == WebHeaderCollectionType.HttpWebRequest) 
            {
                if (HInfo[headerName].IsRequestRestricted) 
                {
                    throw new ArgumentException(!Equals(headerName, HttpKnownHeaderNames.Host) ? SR.GetString(SR.net_headerrestrict) :
                        SR.GetString(SR.net_headerrestrict_resp, HttpKnownHeaderNames.Host), "name");
                } 
            }
            else if (m_Type == WebHeaderCollectionType.HttpListenerResponse) 
            { 
                if (HInfo[headerName].IsResponseRestricted)
                { 
                    throw new ArgumentException(SR.GetString(SR.net_headerrestrict_resp, headerName), "name");
                }
            }
        } 

        // 
        // Our Public METHOD set, most are inherited from NameValueCollection, 
        //  not all methods from NameValueCollection are listed, even though usable -
        // 
        //  this includes
        //  Add(name, value)
        //  Add(header)
        //  this[name] {set, get} 
        //  Remove(name), returns bool
        //  Remove(name), returns void 
        //  Set(name, value) 
        //  ToString()
        // 
        //  SplitValue(name, value)
        //  ToByteArray()
        //  ParseHeaders(char [], ...)
        //  ParseHeaders(byte [], ...) 
        //
 
        // Add more headers; if "name" already exists it will 
        // add concatenated value
 

        // Add -
        //  Routine Description:
        //      Adds headers with validation to see if they are "proper" headers. 
        //      Will cause header to be concat to existing if already found.
        //      If the header is a special header, listed in RestrictedHeaders object, 
        //      then this call will cause an exception indication as such. 
        //  Arguments:
        //      name - header-name to add 
        //      value - header-value to add, a header is already there, will concat this value
        //  Return Value:
        //      None
 
        /// 
        ///     
        ///       Adds a new header with the indicated name and value. 
        ///    
        ///  
        public override void Add(string name, string value) {
            name = CheckBadChars(name, false);
            ThrowOnRestrictedHeader(name);
            value = CheckBadChars(value, true); 
            GlobalLog.Print("WebHeaderCollection::Add() calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (value!=null && value.Length>ushort.MaxValue) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue));
                } 
            }
            NormalizeCommonHeaders();
            InvalidateCachedArrays();
            InnerCollection.Add(name, value); 
        }
 
 
        // Add -
        // Routine Description: 
        //     Adds headers with validation to see if they are "proper" headers.
        //     Assumes a combined a "Name: Value" string, and parses the two parts out.
        //     Will cause header to be concat to existing if already found.
        //     If the header is a speical header, listed in RestrictedHeaders object, 
        //     then this call will cause an exception indication as such.
        // Arguments: 
        //     header - header name: value pair 
        // Return Value:
        //     None 

        /// 
        ///    
        ///       Adds the indicated header. 
        ///    
        ///  
        public void Add(string header) { 
            if ( ValidationHelper.IsBlankString(header) ) {
                throw new ArgumentNullException("header"); 
            }
            int colpos = header.IndexOf(':');
            // check for badly formed header passed in
            if (colpos<0) { 
                throw new ArgumentException(SR.GetString(SR.net_WebHeaderMissingColon), "header");
            } 
            string name = header.Substring(0, colpos); 
            string value = header.Substring(colpos+1);
            name = CheckBadChars(name, false); 
            ThrowOnRestrictedHeader(name);
            value = CheckBadChars(value, true);
            GlobalLog.Print("WebHeaderCollection::Add(" + header + ") calling InnerCollection.Add() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) { 
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                } 
            }
            NormalizeCommonHeaders(); 
            InvalidateCachedArrays();
            InnerCollection.Add(name, value);
        }
 
        // Set -
        // Routine Description: 
        //     Sets headers with validation to see if they are "proper" headers. 
        //     If the header is a special header, listed in RestrictedHeaders object,
        //     then this call will cause an exception indication as such. 
        // Arguments:
        //     name - header-name to set
        //     value - header-value to set
        // Return Value: 
        //     None
 
        ///  
        ///    
        ///       Sets the specified header to the specified value. 
        ///    
        /// 
        public override void Set(string name, string value) {
            if (ValidationHelper.IsBlankString(name)) { 
                throw new ArgumentNullException("name");
            } 
            name = CheckBadChars(name, false); 
            ThrowOnRestrictedHeader(name);
            value = CheckBadChars(value, true); 
            GlobalLog.Print("WebHeaderCollection::Set() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                }
            } 
            NormalizeCommonHeaders(); 
            InvalidateCachedArrays();
            InnerCollection.Set(name, value); 
        }


        internal void SetInternal(string name, string value) { 
            if (ValidationHelper.IsBlankString(name)) {
                throw new ArgumentNullException("name"); 
            } 
            name = CheckBadChars(name, false);
            value = CheckBadChars(value, true); 
            GlobalLog.Print("WebHeaderCollection::Set() calling InnerCollection.Set() key:[" + name + "], value:[" + value + "]");
            if (m_Type==WebHeaderCollectionType.HttpListenerResponse) {
                if (value!=null && value.Length>ushort.MaxValue) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_headers_toolong, ushort.MaxValue)); 
                }
            } 
            NormalizeCommonHeaders(); 
            InvalidateCachedArrays();
            InnerCollection.Set(name, value); 
        }


        // Remove - 
        // Routine Description:
        //     Removes give header with validation to see if they are "proper" headers. 
        //     If the header is a speical header, listed in RestrictedHeaders object, 
        //     then this call will cause an exception indication as such.
        // Arguments: 
        //     name - header-name to remove
        // Return Value:
        //     None
 
        /// 
        ///    Removes the specified header. 
        ///  
        public override void Remove(string name) {
            if ( ValidationHelper.IsBlankString(name) ) { 
                throw new ArgumentNullException("name");
            }
            ThrowOnRestrictedHeader(name);
            name = CheckBadChars(name,  false); 
            GlobalLog.Print("WebHeaderCollection::Remove() calling InnerCollection.Remove() key:[" + name + "]");
            NormalizeCommonHeaders(); 
            if (m_InnerCollection != null) 
            {
                InvalidateCachedArrays(); 
                m_InnerCollection.Remove(name);
            }
        }
 

        // GetValues 
        // Routine Description: 
        //     This method takes a header name and returns a string array representing
        //     the individual values for that headers. For example, if the headers 
        //     contained the line Accept: text/plain, text/html then
        //     GetValues("Accept") would return an array of two strings: "text/plain"
        //     and "text/html".
        // Arguments: 
        //     header      - Name of the header.
        // Return Value: 
        //     string[] - array of parsed string objects 

        ///  
        ///    
        ///       Gets an array of header values stored in a
        ///       header.
        ///     
        /// 
        public override string[] GetValues(string header) { 
            // This method doesn't work with common headers.  Dump common headers into the pool. 
            NormalizeCommonHeaders();
 
            // First get the information about the header and the values for
            // the header.
            HeaderInfo Info = HInfo[header];
            string[] Values = InnerCollection.GetValues(header); 
            // If we have no information about the header or it doesn't allow
            // multiple values, just return the values. 
            if (Info == null || Values == null || !Info.AllowMultiValues) { 
                return Values;
            } 
            // Here we have a multi value header. We need to go through
            // each entry in the multi values array, and if an entry itself
            // has multiple values we'll need to combine those in.
            // 
            // We do some optimazation here, where we try not to copy the
            // values unless there really is one that have multiple values. 
            string[] TempValues; 
            ArrayList ValueList = null;
            int i; 
            for (i = 0; i < Values.Length; i++) {
                // Parse this value header.
                TempValues = Info.Parser(Values[i]);
                // If we don't have an array list yet, see if this 
                // value has multiple values.
                if (ValueList == null) { 
                    // See if it has multiple values. 
                    if (TempValues.Length > 1) {
                        // It does, so we need to create an array list that 
                        // represents the Values, then trim out this one and
                        // the ones after it that haven't been parsed yet.
                        ValueList = new ArrayList(Values);
                        ValueList.RemoveRange(i, Values.Length - i); 
                        ValueList.AddRange(TempValues);
                    } 
                } 
                else {
                    // We already have an ArrayList, so just add the values. 
                    ValueList.AddRange(TempValues);
                }
            }
            // See if we have an ArrayList. If we don't, just return the values. 
            // Otherwise convert the ArrayList to a string array and return that.
            if (ValueList != null) { 
                string[] ReturnArray = new string[ValueList.Count]; 
                ValueList.CopyTo(ReturnArray);
                return ReturnArray; 
            }
            return Values;
        }
 

        // ToString()  - 
        // Routine Description: 
        //     Generates a string representation of the headers, that is ready to be sent except for it being in string format:
        //     the format looks like: 
        //
        //     Header-Name: Header-Value\r\n
        //     Header-Name2: Header-Value2\r\n
        //     ... 
        //     Header-NameN: Header-ValueN\r\n
        //     \r\n 
        // 
        //     Uses the string builder class to Append the elements together.
        // Arguments: 
        //     None.
        // Return Value:
        //     string
 
        /// 
        ///  
        ///     
        ///       Obsolete.
        ///     
        /// 
        public override string ToString() {
            string result = GetAsString(this, false, false);
            GlobalLog.Print("WebHeaderCollection::ToString: \r\n" + result); 
            return result;
        } 
 
        internal string ToString(bool forTrace)
        { 
            return GetAsString(this, false, true);
        }

 
        //
        // if winInetCompat = true then it will not insert spaces after ':' 
        // and it will output "~U" header first 
        //
        internal static string GetAsString(NameValueCollection cc, 
                                           bool                winInetCompat,
                                           bool                forTrace) {
#if FEATURE_PAL
            if (winInetCompat) { 
                throw new InvalidOperationException();
            } 
#endif // FEATURE_PAL 

            if (cc == null || cc.Count == 0) { 
                return "\r\n";
            }
            StringBuilder sb = new StringBuilder(ApproxAveHeaderLineSize*cc.Count);
            string statusLine; 
            statusLine = cc[string.Empty];
            if (statusLine != null) { 
                sb.Append(statusLine).Append("\r\n"); 
            }
            for (int i = 0; i < cc.Count ; i++) { 
                string key = cc.GetKey(i) as string;
                string val = cc.Get(i) as string;
                /*
                if (forTrace) 
                {
                    // Put a condition here that if we are using basic auth, 
                    // we shouldn't put the authorization header. Otherwise 
                    // the password will get saved in the trace.
                    if (using basic) 
                        continue;
                }
                */
                if (ValidationHelper.IsBlankString(key)) { 
                    continue;
                } 
                sb.Append(key); 
                if (winInetCompat) {
                    sb.Append(':'); 
                }
                else {
                    sb.Append(": ");
                } 
                sb.Append(val).Append("\r\n");
            } 
            if (!forTrace) 
                sb.Append("\r\n");
            return sb.ToString(); 
        }


        // ToByteArray()  - 
        // Routine Description:
        //     Generates a byte array representation of the headers, that is ready to be sent. 
        //     So it Serializes our headers into a byte array suitable for sending over the net. 
        //
        //     the format looks like: 
        //
        //     Header-Name1: Header-Value1\r\n
        //     Header-Name2: Header-Value2\r\n
        //     ... 
        //     Header-NameN: Header-ValueN\r\n
        //     \r\n 
        // 
        //     Uses the ToString() method to generate, and then performs conversion.
        // 
        //     Performance Note:  Why are we not doing a single copy/covert run?
        //     As the code before used to know the size of the output!
        //     Because according to Demitry, its cheaper to copy the headers twice,
        //     then it is to call the UNICODE to ANSI conversion code many times. 
        // Arguments:
        //     None. 
        // Return Value: 
        //     byte [] - array of bytes values
 
        /// 
        /// 
        ///    
        ///       Obsolete. 
        ///    
        ///  
        public byte[] ToByteArray() { 
            // Make sure the buffer is big enough.
            string tempStr = ToString(); 
            //
            // Use the string of headers, convert to Char Array,
            //  then convert to Bytes,
            //  serializing finally into the buffer, along the way. 
            //
            byte[] buffer = HeaderEncoding.GetBytes(tempStr); 
            return buffer; 
        }
 
        /// 
        ///    Tests if access to the HTTP header with the provided name is accessible for setting.
        /// 
        public static bool IsRestricted(string headerName) 
        {
            return IsRestricted(headerName, false); 
        } 

        public static bool IsRestricted(string headerName, bool response) 
        {
            return response ? HInfo[CheckBadChars(headerName, false)].IsResponseRestricted : HInfo[CheckBadChars(headerName, false)].IsRequestRestricted;
        }
 

        ///  
        ///     
        ///       Initializes a new instance of the 
        ///       class. 
        ///    
        /// 
        public WebHeaderCollection() : base(DBNull.Value)
        { 
        }
 
        internal WebHeaderCollection(WebHeaderCollectionType type) : base(DBNull.Value) 
        {
            m_Type = type; 
            if (type == WebHeaderCollectionType.HttpWebResponse)
                m_CommonHeaders = new string[s_CommonHeaderNames.Length - 1];  // Minus one for the sentinel.
        }
 
        //This is for Cache
        internal WebHeaderCollection(NameValueCollection cc): base(DBNull.Value) 
        { 
            m_InnerCollection = new NameValueCollection(cc.Count + 2, CaseInsensitiveAscii.StaticInstance);
            int len = cc.Count; 
            for (int i = 0; i < len; ++i) {
                String key = cc.GetKey(i);
                String[] values = cc.GetValues(i);
                if (values != null) { 
                    for (int j = 0; j < values.Length; j++) {
                        InnerCollection.Add(key, values[j]); 
                    } 
                }
                else { 
                    InnerCollection.Add(key, null);
                }
            }
        } 

        // 
        // ISerializable constructor 
        //
        ///  
        ///    [To be supplied.]
        /// 
        protected WebHeaderCollection(SerializationInfo serializationInfo, StreamingContext streamingContext) :
            base(DBNull.Value) 
        {
            int count = serializationInfo.GetInt32("Count"); 
            m_InnerCollection = new NameValueCollection(count + 2, CaseInsensitiveAscii.StaticInstance); 
            for (int i = 0; i < count; i++) {
                string headerName = serializationInfo.GetString(i.ToString(NumberFormatInfo.InvariantInfo)); 
                string headerValue = serializationInfo.GetString((i+count).ToString(NumberFormatInfo.InvariantInfo));
                GlobalLog.Print("WebHeaderCollection::.ctor(ISerializable) calling InnerCollection.Add() key:[" + headerName + "], value:[" + headerValue + "]");
                InnerCollection.Add(headerName, headerValue);
            } 
        }
 
        public override void OnDeserialization(object sender) { 
            //
 

        }

        // 
        // ISerializable method
        // 
        ///  
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] 		
        public override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) { 
            //
            // for now disregard streamingContext.
            //
            NormalizeCommonHeaders(); 
            serializationInfo.AddValue("Count", Count);
            for (int i = 0; i < Count; i++) 
            { 
                serializationInfo.AddValue(i.ToString(NumberFormatInfo.InvariantInfo), GetKey(i));
                serializationInfo.AddValue((i + Count).ToString(NumberFormatInfo.InvariantInfo), Get(i)); 
            }
        }

 
        // we use this static class as a helper class to encode/decode HTTP headers.
        // what we need is a 1-1 correspondence between a char in the range U+0000-U+00FF 
        // and a byte in the range 0x00-0xFF (which is the range that can hit the network). 
        // The Latin-1 encoding (ISO-88591-1) (GetEncoding(28591)) works for byte[] to string, but is a little slow.
        // It doesn't work for string -> byte[] because of best-fit-mapping problems. 
        internal static class HeaderEncoding
        {
            internal static unsafe string GetString(byte[] bytes, int byteIndex, int byteCount)
            { 
                fixed(byte* pBytes = bytes)
                    return GetString(pBytes + byteIndex, byteCount); 
            } 

            internal static unsafe string GetString(byte* pBytes, int byteCount) 
            {
                if (byteCount < 1)
                    return "";
 
                string s = new String('\0', byteCount);
 
                fixed (char* pStr = s) 
                {
                    char* pString = pStr; 
                    while (byteCount >= 8)
                    {
                        pString[0] = (char) pBytes[0];
                        pString[1] = (char) pBytes[1]; 
                        pString[2] = (char) pBytes[2];
                        pString[3] = (char) pBytes[3]; 
                        pString[4] = (char) pBytes[4]; 
                        pString[5] = (char) pBytes[5];
                        pString[6] = (char) pBytes[6]; 
                        pString[7] = (char) pBytes[7];
                        pString += 8;
                        pBytes += 8;
                        byteCount -= 8; 
                    }
                    for (int i = 0; i < byteCount; i++) 
                    { 
                        pString[i] = (char) pBytes[i];
                    } 
                }

                return s;
            } 

            internal static int GetByteCount(string myString) { 
                return myString.Length; 
            }
            internal unsafe static void GetBytes(string myString, int charIndex, int charCount, byte[] bytes, int byteIndex) { 
                if (myString.Length==0) {
                    return;
                }
                fixed (byte *bufferPointer = bytes) { 
                    byte* newBufferPointer = bufferPointer + byteIndex;
                    int finalIndex = charIndex + charCount; 
                    while (charIndex 
            // TEXT           = 
            // CTL            =  
            // SP             = 
            // HT             = 
            // CR             = 
            // LF             =  
            // LWS            = [CR LF] 1*( SP | HT )
            // CHAR           =  
            // token          = 1* 
            // separators     = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
            // quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> ) 
            // qdtext         = >
            // quoted-pair    = "\" CHAR
            //
 
            //
            // At each iteration of the following loop we expect to parse a single HTTP header entirely. 
            // 
            for (;;) {
                // 
                // trim leading whitespaces (LWS) just for extra robustness, in fact if there are leading white spaces then:
                // 1) it could be that after the status line we might have spaces. handle this.
                // 2) this should have been detected to be a multiline header so there'll be no spaces and we'll spend some time here.
                // 
                headerName = string.Empty;
                headerValue = string.Empty; 
                spaceAfterLf = false; 
                headerMultiLineValue = null;
 
                if (Count == 0) {
                    //
                    // so, restrict this extra trimming only on the first header line
                    // 
                    while (index < size) {
                         ch = (char) byteBuffer[index]; 
                         if (ch == ' ' || ch == '\t') { 
                             ++index;
                            if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                                parseStatus = DataParseStatus.DataTooBig;
                                goto quit;
                            }
                        } 
                        else {
                            break; 
                        } 
                    }
 
                    if (index==size) {
                        //
                        // we reached the end of the buffer. ask for more data.
                        // 
                        parseStatus = DataParseStatus.NeedMoreData;
                        goto quit; 
                    } 
                }
 
                //
                // what we have here is the beginning of a new header
                //
                headerNameStartOffset = index; 

                while (index < size) { 
                    ch = (char) byteBuffer[index]; 
                    if (ch != ':' && ch != '\n') {
                        if (ch > ' ') { 
                            //
                            // if there's an illegal character we should return DataParseStatus.Invalid
                            // instead we choose to be flexible, try to trim it, but include it in the string
                            // 
                            headerNameEndOffset = index;
                        } 
                        ++index; 
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig; 
                            goto quit;
                        }
                    }
                    else { 
                        if (ch == ':') {
                            ++index; 
                            if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                                parseStatus = DataParseStatus.DataTooBig;
                                goto quit; 
                            }
                        }
                        break;
                    } 
                }
                if (index==size) { 
                    // 
                    // we reached the end of the buffer. ask for more data.
                    // 
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }
 
startOfValue:
                // 
                // skip all [' ','\t','\r','\n'] characters until HeaderValue starts 
                // if we didn't find any headers yet, we set numberOfLf to 1
                // so that we take the '\n' from the status line into account 
                //

                numberOfLf = (Count == 0 && headerNameEndOffset < 0) ? 1 : 0;
                while (index=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit; 
                        }
                    }
                    else {
                        break; 
                    }
                } 
                if (numberOfLf==2 || (numberOfLf==1 && !spaceAfterLf)) { 
                    //
                    // if we've counted two '\n' we got at the end of the headers even if we're past the end of the buffer 
                    // if we've counted one '\n' and the first character after that was a ' ' or a '\t'
                    // no matter if we found a ':' or not, treat this as an empty header name.
                    //
                    goto addHeader; 
                }
                if (index==size) { 
                    // 
                    // we reached the end of the buffer. ask for more data.
                    // 
                    parseStatus = DataParseStatus.NeedMoreData;
                    goto quit;
                }
 
                headerValueStartOffset = index;
 
                while (index ' ') {
                            headerValueEndOffset = index;
                        }
                        ++index; 
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig; 
                            goto quit; 
                        }
                    } 
                    else {
                        break;
                    }
                } 
                if (index==size) {
                    // 
                    // we reached the end of the buffer. ask for more data. 
                    //
                    parseStatus = DataParseStatus.NeedMoreData; 
                    goto quit;
                }

                // 
                // at this point we found either a '\n' or the end of the headers
                // hence we are at the end of the Header Line. 4 options: 
                // 1) need more data 
                // 2) if we find two '\n' => end of headers
                // 3) if we find one '\n' and a ' ' or a '\t' => multiline header 
                // 4) if we find one '\n' and a valid char => next header
                //
                numberOfLf = 0;
                while (index=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) {
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit; 
                        }
                    } 
                    else { 
                        break;
                    } 
                }
                if (index==size && numberOfLf<2) {
                    //
                    // we reached the end of the buffer but not of the headers. ask for more data. 
                    //
                    parseStatus = DataParseStatus.NeedMoreData; 
                    goto quit; 
                }
 
addHeader:
                if (headerValueStartOffset>=0 && headerValueStartOffset>headerNameEndOffset && headerValueEndOffset>=headerValueStartOffset) {
                    //
                    // Encoding fastest way to build the UNICODE string off the byte[] 
                    //
                    headerValue = HeaderEncoding.GetString(byteBuffer + headerValueStartOffset, headerValueEndOffset - headerValueStartOffset + 1); 
                } 

                // 
                // if we got here from the beginning of the for loop, headerMultiLineValue will be null
                // otherwise it will contain the headerValue constructed for the multiline header
                // add this line as well to it, separated by a single space
                // 
                headerMultiLineValue = (headerMultiLineValue==null ? headerValue : headerMultiLineValue + " " + headerValue);
 
                if (index < size && numberOfLf == 1) { 
                    ch = (char) byteBuffer[index];
                    if (ch == ' ' || ch == '\t') { 
                        //
                        // since we found only one Lf and the next header line begins with a Lws,
                        // this is the beginning of a multiline header.
                        // parse the next line into headerValue later it will be added to headerMultiLineValue 
                        //
                        ++index; 
                        if (maximumResponseHeadersLength>=0 && ++localTotalResponseHeadersLength>=maximumResponseHeadersLength) { 
                            parseStatus = DataParseStatus.DataTooBig;
                            goto quit; 
                        }
                        goto startOfValue;
                    }
                } 

                if (headerNameStartOffset>=0 && headerNameEndOffset>=headerNameStartOffset) { 
                    // 
                    // Encoding is the fastest way to build the UNICODE string off the byte[]
                    // 
                    headerName = HeaderEncoding.GetString(byteBuffer + headerNameStartOffset, headerNameEndOffset - headerNameStartOffset + 1);
                }

                // 
                // now it's finally safe to add the header if we have a name for it
                // 
                if (headerName.Length>0) { 
                    //
                    // the base clasee will check for pre-existing headerValue and append 
                    // it using commas as indicated in the RFC
                    //
                    GlobalLog.Print("WebHeaderCollection::ParseHeaders() calling AddInternal() key:[" + headerName + "], value:[" + headerMultiLineValue + "]");
                    AddInternal(headerName, headerMultiLineValue); 
                }
 
                // 
                // and update unparsed
                // 
                totalResponseHeadersLength = localTotalResponseHeadersLength;
                unparsed = index;

                if (numberOfLf==2) { 
                    parseStatus = DataParseStatus.Done;
                    goto quit; 
                } 

            } // for (;;) 

quit:
            GlobalLog.Leave("WebHeaderCollection::ParseHeaders() returning parseStatus:" + parseStatus.ToString());
            if (parseStatus == DataParseStatus.Invalid) { 
                parseError.Section = WebParseErrorSection.ResponseHeader;
                parseError.Code    = parseErrorCode; 
            } 

            return parseStatus; 
            }
        }

        // 
        // Alternative parsing that follows RFC2616.  Like the above, this trims both sides of the header value and replaces
        // folding with a single space. 
        // 
        private enum RfcChar : byte
        { 
            High = 0,
            Reg,
            Ctl,
            CR, 
            LF,
            WS, 
            Colon, 
            Delim
        } 

        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,    RfcChar.LF,    RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.CR,    RfcChar.Ctl,   RfcChar.Ctl,
            RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl, 
            RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl,   RfcChar.Ctl, 
            RfcChar.WS,    RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Delim, RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Colon, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Delim,
            RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, RfcChar.Delim, RfcChar.Delim, RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg, 
            RfcChar.Reg,   RfcChar.Reg,   RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Delim, RfcChar.Reg,   RfcChar.Ctl,
        };

        internal unsafe DataParseStatus ParseHeadersStrict( 
                byte[] buffer,
                int size, 
                ref int unparsed, 
                ref int totalResponseHeadersLength,
                int maximumResponseHeadersLength, 
                ref WebParseError parseError)
        {
            GlobalLog.Enter("WebHeaderCollection::ParseHeadersStrict(): size:" + size.ToString() + ", unparsed:" + unparsed.ToString() + " buffer:[" + Encoding.ASCII.GetString(buffer, unparsed, Math.Min(256, size-unparsed)) + "]");
 
            WebParseErrorCode parseErrorCode = WebParseErrorCode.Generic;
            DataParseStatus parseStatus = DataParseStatus.Invalid; 
 
            int i = unparsed;
            RfcChar ch; 
            int effectiveSize = maximumResponseHeadersLength <= 0 ? Int32.MaxValue : maximumResponseHeadersLength - totalResponseHeadersLength + i;
            DataParseStatus sizeError = DataParseStatus.DataTooBig;
            if (size < effectiveSize)
            { 
                effectiveSize = size;
                sizeError = DataParseStatus.NeedMoreData; 
            } 

            // Verify the size. 
            if (i >= effectiveSize)
            {
                parseStatus = sizeError;
                goto quit; 
            }
 
            fixed (byte* byteBuffer = buffer) 
            {
                while (true) 
                {
                    // If this is CRLF, actually we're done.
                    if (byteBuffer[i] == '\r')
                    { 
                        if (++i == effectiveSize)
                        { 
                            parseStatus = sizeError; 
                            goto quit;
                        } 

                        if (byteBuffer[i++] == '\n')
                        {
                            totalResponseHeadersLength += i - unparsed; 
                            unparsed = i;
                            parseStatus = DataParseStatus.Done; 
                            goto quit; 
                        }
 
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit;
                    } 

                    // Find the header name; only regular characters allowed. 
                    int iBeginName = i; 
                    for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.Reg; i++);
                    if (i == effectiveSize) 
                    {
                        parseStatus = sizeError;
                        goto quit;
                    } 
                    if (i == iBeginName)
                    { 
                        parseStatus = DataParseStatus.Invalid; 
                        parseErrorCode = WebParseErrorCode.InvalidHeaderName;
                        goto quit; 
                    }

                    // Read to a colon.
                    int iEndName = i - 1; 
                    int crlf = 0;  // 1 = cr, 2 = crlf
                    for (; i < effectiveSize && (ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) != RfcChar.Colon; i++) 
                    { 
                        switch (ch)
                        { 
                            case RfcChar.WS:
                                if (crlf == 1)
                                {
                                    break; 
                                }
                                crlf = 0; 
                                continue; 

                            case RfcChar.CR: 
                                if (crlf == 0)
                                {
                                    crlf = 1;
                                    continue; 
                                }
                                break; 
 
                            case RfcChar.LF:
                                if (crlf == 1) 
                                {
                                    crlf = 2;
                                    continue;
                                } 
                                break;
                        } 
                        parseStatus = DataParseStatus.Invalid; 
                        parseErrorCode = WebParseErrorCode.CrLfError;
                        goto quit; 
                    }
                    if (i == effectiveSize)
                    {
                        parseStatus = sizeError; 
                        goto quit;
                    } 
                    if (crlf != 0) 
                    {
                        parseStatus = DataParseStatus.Invalid; 
                        parseErrorCode = WebParseErrorCode.IncompleteHeaderLine;
                        goto quit;
                    }
 
                    // Skip the colon.
                    if (++i == effectiveSize) 
                    { 
                        parseStatus = sizeError;
                        goto quit; 
                    }

                    // Read the value.  crlf = 3 means in the whitespace after a CRLF
                    int iBeginValue = -1; 
                    int iEndValue = -1;
                    StringBuilder valueAccumulator = null; 
                    for (; i < effectiveSize && ((ch = byteBuffer[i] > 127 ? RfcChar.High : RfcCharMap[byteBuffer[i]]) == RfcChar.WS || crlf != 2); i++) 
                    {
                        switch (ch) 
                        {
                            case RfcChar.WS:
                                if (crlf == 1)
                                { 
                                    break;
                                } 
                                if (crlf == 2) 
                                {
                                    crlf = 3; 
                                }
                                continue;

                            case RfcChar.CR: 
                                if (crlf == 0)
                                { 
                                    crlf = 1; 
                                    continue;
                                } 
                                break;

                            case RfcChar.LF:
                                if (crlf == 1) 
                                {
                                    crlf = 2; 
                                    continue; 
                                }
                                break; 

                            case RfcChar.High:
                            case RfcChar.Colon:
                            case RfcChar.Delim: 
                            case RfcChar.Reg:
                                if (crlf == 1) 
                                { 
                                    break;
                                } 
                                if (crlf == 3)
                                {
                                    crlf = 0;
                                    if (iBeginValue != -1) 
                                    {
                                        string s = HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1); 
                                        if (valueAccumulator == null) 
                                        {
                                            valueAccumulator = new StringBuilder(s, s.Length * 5); 
                                        }
                                        else
                                        {
                                            valueAccumulator.Append(" "); 
                                            valueAccumulator.Append(s);
                                        } 
                                    } 
                                    iBeginValue = -1;
                                } 
                                if (iBeginValue == -1)
                                {
                                    iBeginValue = i;
                                } 
                                iEndValue = i;
                                continue; 
                        } 
                        parseStatus = DataParseStatus.Invalid;
                        parseErrorCode = WebParseErrorCode.CrLfError; 
                        goto quit;
                    }
                    if (i == effectiveSize)
                    { 
                        parseStatus = sizeError;
                        goto quit; 
                    } 

                    // Make the value. 
                    string sValue = iBeginValue == -1 ? "" : HeaderEncoding.GetString(byteBuffer + iBeginValue, iEndValue - iBeginValue + 1);
                    if (valueAccumulator != null)
                    {
                        if (sValue.Length != 0) 
                        {
                            valueAccumulator.Append(" "); 
                            valueAccumulator.Append(sValue); 
                        }
                        sValue = valueAccumulator.ToString(); 
                    }

                    // Make the name.  See if it's a common header first.
                    string sName = null; 
                    int headerNameLength = iEndName - iBeginName + 1;
                    if (m_CommonHeaders != null) 
                    { 
                        int iHeader = s_CommonHeaderHints[byteBuffer[iBeginName] & 0x1f];
                        if (iHeader >= 0) 
                        {
                            while (true)
                            {
                                string s = s_CommonHeaderNames[iHeader++]; 

                                // Not found if we get to a shorter header or one with a different first character. 
                                if (s.Length < headerNameLength || CaseInsensitiveAscii.AsciiToLower[byteBuffer[iBeginName]] != CaseInsensitiveAscii.AsciiToLower[s[0]]) 
                                    break;
 
                                // Keep looking if the common header is too long.
                                if (s.Length > headerNameLength)
                                    continue;
 
                                int j;
                                byte* pBuffer = byteBuffer + iBeginName + 1; 
                                for (j = 1; j < s.Length; j++) 
                                {
                                    // Avoid the case-insensitive compare in the common case where they match. 
                                    if (*(pBuffer++) != s[j] && CaseInsensitiveAscii.AsciiToLower[*(pBuffer - 1)] != CaseInsensitiveAscii.AsciiToLower[s[j]])
                                        break;
                                }
                                if (j == s.Length) 
                                {
                                    // Set it to the appropriate index. 
                                    m_NumCommonHeaders++; 
                                    iHeader--;
                                    if (m_CommonHeaders[iHeader] == null) 
                                    {
                                        m_CommonHeaders[iHeader] = sValue;
                                    }
                                    else 
                                    {
                                        // Don't currently handle combining multiple header instances in the common header case. 
                                        // Nothing to do but punt them all to the NameValueCollection. 
                                        NormalizeCommonHeaders();
                                        AddInternalNotCommon(s, sValue); 
                                    }

                                    sName = s;
                                    break; 
                                }
                            } 
                        } 
                    }
 
                    // If it wasn't a common header, add it to the hash.
                    if (sName == null)
                    {
                        sName = HeaderEncoding.GetString(byteBuffer + iBeginName, headerNameLength); 
                        AddInternalNotCommon(sName, sValue);
                    } 
 
                    totalResponseHeadersLength += i - unparsed;
                    unparsed = i; 
                }
            }

quit: 
            GlobalLog.Leave("WebHeaderCollection::ParseHeadersStrict() returning parseStatus:" + parseStatus.ToString());
 
            if (parseStatus == DataParseStatus.Invalid) { 
                parseError.Section = WebParseErrorSection.ResponseHeader;
                parseError.Code    = parseErrorCode; 
            }

            return parseStatus;
        } 

        // 
        // Keeping this version for backwards compatibility (mostly with reflection).  Remove some day, along with the interface 
        // explicit reimplementation.
        // 
        /// 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)]
        void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        { 
            GetObjectData(serializationInfo, streamingContext);
        } 
 
        // Override Get() to check the common headers.
        public override string Get(string name) 
        {
            // In this case, need to make sure name doesn't have any Unicode since it's being used as an index into tables.
            if (m_CommonHeaders != null && name != null && name.Length > 0 && name[0] < 256)
            { 
                int iHeader = s_CommonHeaderHints[name[0] & 0x1f];
                if (iHeader >= 0) 
                { 
                    while (true)
                    { 
                        string s = s_CommonHeaderNames[iHeader++];

                        // Not found if we get to a shorter header or one with a different first character.
                        if (s.Length < name.Length || CaseInsensitiveAscii.AsciiToLower[name[0]] != CaseInsensitiveAscii.AsciiToLower[s[0]]) 
                            break;
 
                        // Keep looking if the common header is too long. 
                        if (s.Length > name.Length)
                            continue; 

                        int j;
                        for (j = 1; j < s.Length; j++)
                        { 
                            // Avoid the case-insensitive compare in the common case where they match.
                            if (name[j] != s[j] && (name[j] > 255 || CaseInsensitiveAscii.AsciiToLower[name[j]] != CaseInsensitiveAscii.AsciiToLower[s[j]])) 
                                break; 
                        }
                        if (j == s.Length) 
                        {
                            // Get the appropriate header.
                            return m_CommonHeaders[iHeader - 1];
                        } 
                    }
                } 
            } 

            // Fall back to normal lookup. 
            if (m_InnerCollection == null)
                return null;
            return m_InnerCollection.Get(name);
        } 

 
        // 
        // Additional overrides required to fully orphan the base implementation.
        // 
        public override IEnumerator GetEnumerator()
        {
            NormalizeCommonHeaders();
            return new NameObjectKeysEnumerator(InnerCollection); 
        }
 
        public override int Count 
        {
            get 
            {
                return (m_InnerCollection == null ? 0 : m_InnerCollection.Count) + m_NumCommonHeaders;
            }
        } 

        public override KeysCollection Keys 
        { 
            get
            { 
                NormalizeCommonHeaders();
                return InnerCollection.Keys;
            }
        } 

        internal override bool InternalHasKeys() 
        { 
            NormalizeCommonHeaders();
            if (m_InnerCollection == null) 
                return false;
            return m_InnerCollection.HasKeys();
        }
 
        public override string Get(int index)
        { 
            NormalizeCommonHeaders(); 
            return InnerCollection.Get(index);
        } 

        public override string[] GetValues(int index)
        {
            NormalizeCommonHeaders(); 
            return InnerCollection.GetValues(index);
        } 
 
        public override string GetKey(int index)
        { 
            NormalizeCommonHeaders();
            return InnerCollection.GetKey(index);
        }
 
        public override string[] AllKeys
        { 
            get 
            {
                NormalizeCommonHeaders(); 
                return InnerCollection.AllKeys;
            }
        }
 
        public override void Clear()
        { 
            m_CommonHeaders = null; 
            m_NumCommonHeaders = 0;
            InvalidateCachedArrays(); 
            if (m_InnerCollection != null)
                m_InnerCollection.Clear();
        }
    } // class WebHeaderCollection 

 
    internal class CaseInsensitiveAscii : IEqualityComparer, IComparer{ 
        // ASCII char ToLower table
        internal static readonly CaseInsensitiveAscii StaticInstance = new CaseInsensitiveAscii(); 
        internal static readonly byte[] AsciiToLower = new byte[] {
              0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
             10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
             20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 
             30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
             40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 
             50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 
             60, 61, 62, 63, 64, 97, 98, 99,100,101, //  60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
            102,103,104,105,106,107,108,109,110,111, //  70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 
            112,113,114,115,116,117,118,119,120,121, //  80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
            122, 91, 92, 93, 94, 95, 96, 97, 98, 99, //  90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
            100,101,102,103,104,105,106,107,108,109,
            110,111,112,113,114,115,116,117,118,119, 
            120,121,122,123,124,125,126,127,128,129,
            130,131,132,133,134,135,136,137,138,139, 
            140,141,142,143,144,145,146,147,148,149, 
            150,151,152,153,154,155,156,157,158,159,
            160,161,162,163,164,165,166,167,168,169, 
            170,171,172,173,174,175,176,177,178,179,
            180,181,182,183,184,185,186,187,188,189,
            190,191,192,193,194,195,196,197,198,199,
            200,201,202,203,204,205,206,207,208,209, 
            210,211,212,213,214,215,216,217,218,219,
            220,221,222,223,224,225,226,227,228,229, 
            230,231,232,233,234,235,236,237,238,239, 
            240,241,242,243,244,245,246,247,248,249,
            250,251,252,253,254,255 
        };

        // ASCII string case insensitive hash function
        public int GetHashCode(object myObject) { 
            string myString = myObject as string;
            if (myObject == null) { 
                return 0; 
            }
            int myHashCode = myString.Length; 
            if (myHashCode == 0) {
                return 0;
            }
            myHashCode ^= AsciiToLower[(byte)myString[0]]<<24 ^ AsciiToLower[(byte)myString[myHashCode-1]]<<16; 
            return myHashCode;
        } 
 
        // ASCII string case insensitive comparer
        public int Compare(object firstObject, object secondObject) { 
            string firstString = firstObject as string;
            string secondString = secondObject as string;
            if (firstString==null) {
                return secondString == null ? 0 : -1; 
            }
            if (secondString == null) { 
                return 1; 
            }
            int result = firstString.Length - secondString.Length; 
            int comparisons = result > 0 ? secondString.Length : firstString.Length;
            int difference, index = 0;
            while ( index < comparisons ) {
                difference = (int)(AsciiToLower[ firstString[index] ] - AsciiToLower[ secondString[index] ]); 
                if ( difference != 0 ) {
                    result = difference; 
                    break; 
                }
                index++; 
            }
            return result;
        }
 
        // ASCII string case insensitive hash function
        int FastGetHashCode(string myString) { 
            int myHashCode = myString.Length; 
            if (myHashCode!=0) {
                myHashCode ^= AsciiToLower[(byte)myString[0]]<<24 ^ AsciiToLower[(byte)myString[myHashCode-1]]<<16; 
            }
            return myHashCode;
        }
 
        // ASCII string case insensitive comparer
        public new bool Equals(object firstObject, object secondObject) { 
            string firstString = firstObject as string; 
            string secondString = secondObject as string;
            if (firstString==null) { 
                return secondString==null;
            }
            if (secondString!=null) {
                int index = firstString.Length; 
                if (index==secondString.Length) {
                    if (FastGetHashCode(firstString)==FastGetHashCode(secondString)) { 
                        int comparisons = firstString.Length; 
                        while (index>0) {
                            index--; 
                            if (AsciiToLower[firstString[index]]!=AsciiToLower[secondString[index]]) {
                                return false;
                            }
                        } 
                        return true;
                    } 
                } 
            }
            return false; 
        }
    }

    internal class HostHeaderString { 

        private bool m_Converted; 
        private string m_String; 
        private byte[] m_Bytes;
 
        internal HostHeaderString() {
            Init(null);
        }
 
        internal HostHeaderString(string s) {
            Init(s); 
        } 

        private void Init(string s) { 
            m_String = s;
            m_Converted = false;
            m_Bytes = null;
        } 

        private void Convert() { 
            if (m_String != null && !m_Converted) { 
                m_Bytes = Encoding.Default.GetBytes(m_String);
                string copy = Encoding.Default.GetString(m_Bytes); 
                if (!(string.Compare(m_String, copy, StringComparison.Ordinal) == 0)) {
                    m_Bytes = Encoding.UTF8.GetBytes(m_String);
                }
            } 
        }
 
        internal string String { 
            get { return m_String; }
            set { 
                Init(value);
            }
        }
 
        internal int ByteCount {
            get { 
                Convert(); 
                return m_Bytes.Length;
            } 
        }

        internal byte[] Bytes {
            get { 
                Convert();
                return m_Bytes; 
            } 
        }
 
        internal void Copy(byte[] destBytes, int destByteIndex) {
            Convert();
            Array.Copy(m_Bytes, 0, destBytes, destByteIndex, m_Bytes.Length);
        } 

    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK