HttpWebRequest.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Net / System / Net / HttpWebRequest.cs / 5 / HttpWebRequest.cs

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

namespace System.Net { 
    using System.Collections; 
    using System.Collections.Specialized;
    using System.Globalization; 
    using System.IO;
    using System.IO.Compression;
    using System.Net.Cache;
    using System.Net.Configuration; 
    using System.Runtime.Serialization;
    using System.Security; 
    using System.Security.Cryptography.X509Certificates; 
    using System.Security.Permissions;
    using System.Text; 
    using System.Text.RegularExpressions;
    using System.Threading;
    using System.Net.Security;
    using System.Reflection; 
    using System.ComponentModel;
 
    ///  
    /// 
    ///  is an HTTP-specific implementation of the  class. 
    ///
    ///  Performs the major body of HTTP request processing. Handles
    ///    everything between issuing the HTTP header request to parsing the
    ///    the HTTP response.  At that point, we hand off the request to the response 
    ///    object, where the programmer can query for headers or continue reading, usw.
    ///   
    ///  

 
    [Flags]
    public enum DecompressionMethods{
        None = 0,
        GZip = 1, 
        Deflate = 2
    } 
 

    [Serializable] 
    public class HttpWebRequest : WebRequest, ISerializable {

        //these could have race conditions
        bool m_Saw100Continue; 
        bool m_KeepAlive = true;
        bool m_LockConnection; 
        bool m_NtlmKeepAlive; 
        bool m_PreAuthenticate;
        DecompressionMethods m_AutomaticDecompression; 

        private static class AbortState {
            public const int Public     = 1;
            public const int Internal = 2; 
        }
        // interlocked 
        private int m_Aborted; 

        // 
        // This is set on failure of the request before reattempting a retransmit,
        // we do this on write/read failures so that we can recover from certain failures
        // that may be caused by intermittent server/network failures.
        // Returns: true, if we have seen some kind of failure. 
        //
        // set to true if this request failed during a connect 
 
        bool m_OnceFailed;
 
        bool m_Pipelined = true;
        bool m_Retry = true;
        bool m_HeadersCompleted;
        bool m_IsCurrentAuthenticationStateProxy; 
        bool m_SawInitialResponse;
        bool m_BodyStarted; 
        bool m_RequestSubmitted; 
        bool m_OriginallyBuffered;
        bool m_Extra401Retry; 

        //these should be safe.
        [Flags]
        private enum Booleans : uint { 
            AllowAutoRedirect                       = 0x00000001,
            AllowWriteStreamBuffering               = 0x00000002, 
            ExpectContinue                          = 0x00000004, 

            ProxySet                                = 0x00000010, 

            UnsafeAuthenticatedConnectionSharing    = 0x00000040,
            IsVersionHttp10                         = 0x00000080,
            SendChunked                             = 0x00000100, 
            EnableDecompression                     = 0x00000200,
            IsTunnelRequest                         = 0x00000400, 
            Default = AllowAutoRedirect | AllowWriteStreamBuffering | ExpectContinue 
        }
 

        internal const HttpStatusCode MaxOkStatus = (HttpStatusCode)299;
        private const HttpStatusCode MaxRedirectionStatus = (HttpStatusCode)399;
        private const int RequestLineConstantSize = 12; 
        private const string ContinueHeader = "100-continue";
        internal const string ChunkedHeader = "chunked"; 
        internal const string GZipHeader    = "gzip"; 
        internal const string DeflateHeader    = "deflate";
 

        // default delay on the Stream.Read and Stream.Write operations
        private const int DefaultReadWriteTimeout = 5 * 60 * 1000; // 5 minutes
 
        // time delay that we would wait for continue
        internal const int DefaultContinueTimeout = 350; // ms 
 
        // Size of '  HTTP/x.x\r\n'
        // which are the 
        // unchanging pieces of the
        // request line.
        private static readonly byte[]  HttpBytes = new byte[]{(byte)'H', (byte)'T', (byte)'T', (byte)'P', (byte)'/'};
 
        // Statics used in the 100 Continue timeout mechanism.
        private static readonly WaitCallback s_EndWriteHeaders_Part2Callback = new WaitCallback(EndWriteHeaders_Part2Wrapper); 
        private static readonly TimerThread.Callback s_ContinueTimeoutCallback = new TimerThread.Callback(ContinueTimeoutCallback); 
        private static readonly TimerThread.Queue s_ContinueTimerQueue = TimerThread.GetOrCreateQueue(DefaultContinueTimeout);
        private static readonly TimerThread.Callback s_TimeoutCallback = new TimerThread.Callback(TimeoutCallback); 
        private static readonly WaitCallback s_AbortWrapper = new WaitCallback(AbortWrapper);

        private static int s_UniqueGroupId;
 
        private Booleans                _Booleans = Booleans.Default;
 
        private DateTime                _CachedIfModifedSince = DateTime.MinValue; 

        // Used in the 100 Continue timeout mechanism. 
        private TimerThread.Timer       m_ContinueTimer;
        private InterlockedGate         m_ContinueGate;

        // Holds a WriteStream result to be processed by GetResponse. 
        private object                  m_PendingReturnResult;
 
        // Read and Write async results - corspond to BeginGetResponse(read), and BeginGetRequestStream(write) 
        private LazyAsyncResult         _WriteAResult;
        private LazyAsyncResult         _ReadAResult; 

        // Used by our Connection to block the Request on getting a Connection
        private LazyAsyncResult         _ConnectionAResult;
        // Used by our Connection to block on being able to Read from our Connection 
        private LazyAsyncResult         _ConnectionReaderAResult;
 
        // Once set, the Request either works Async or Sync internally 
        private TriState                _RequestIsAsync;
 
        // Delegate that can be called on Continue Response
        private HttpContinueDelegate    _ContinueDelegate;

        // Link back to the server point used for this request. 
        internal ServicePoint           _ServicePoint;
 
        // this is generated by SetResponse 
        internal HttpWebResponse        _HttpResponse;
 
#if TRAVE
        internal HttpWebResponse _OldResponse;
#endif
 
        // set by Connection code upon completion (can be either CoreResponseData or an Exception)
        private object                  _CoreResponse; 
        private int                     _NestedWriteSideCheck; //To keep track nested responses for Sync case 

        // request values 
        private KnownHttpVerb           _Verb;
        // the actual verb set by caller or default
        private KnownHttpVerb           _OriginVerb;
 
        // our HTTP header response, request, parsing and storage objects
        private WebHeaderCollection     _HttpRequestHeaders; 
 
        // send buffer for output request with headers.
        private byte[]                  _WriteBuffer; 

        // Property to set whether writes can be handled
        private HttpWriteMode           _HttpWriteMode;
 
        // the host, port, and path
        private Uri                     _Uri; 
        // the origin Uri host, port and path that never changes 
        private Uri                     _OriginUri;
 
        // for which response ContentType we will look for and parse the CharacterSet
        private string                  _MediaType;

        // content length 
        private long                    _ContentLength;
 
        // proxy that we are using... 
        private IWebProxy               _Proxy;
        private ProxyChain              _ProxyChain; 

        private string                  _ConnectionGroupName;
        private bool                    m_InternalConnectionGroup;
 
        private AuthenticationState     _ProxyAuthenticationState;
        private AuthenticationState     _ServerAuthenticationState; 
 
        private ICredentials            _AuthInfo;
        private HttpAbortDelegate       _AbortDelegate; 

        //
        // used to prevent Write Buffering,
        //  used otherwise for reposting POST, and PUTs in redirects 
        //
        private ConnectStream           _SubmitWriteStream; 
        private ConnectStream           _OldSubmitWriteStream; 
        private int                     _MaximumAllowedRedirections;
        private int                     _AutoRedirects; 

        //
        // generic version of _AutoRedirects above
        // used to count the number of requests made off this WebRequest 
        //
        private int                     _RerequestCount; 
 
        //
        // Timeout in milliseconds, if a synchronous request takes longer 
        // than timeout, a WebException is thrown
        //
        private int                     _Timeout;
 
        //
        // Used to track relative time out across the use of the request 
        // 
        private TimerThread.Timer       _Timer;
 
        //
        // Timer factory, tied to the _Timeout time.
        //
        private TimerThread.Queue       _TimerQueue; 

        private int                     _RequestContinueCount; 
 
        //
        // Timeout for Read & Write on the Stream that we return through 
        //  GetResponse().GetResponseStream() && GetRequestStream()
        //
        private int                     _ReadWriteTimeout;
 
        private CookieContainer         _CookieContainer;
 
        private int                     _MaximumResponseHeadersLength; 

        private UnlockConnectionDelegate _UnlockDelegate; 


#if !FEATURE_PAL
        // 
        // Our ClientCertificates are non-null, if we are doing client auth
        // 
        private X509CertificateCollection _ClientCertificates; 

#endif // !FEATURE_PAL 

        // size of post data, that needs to be greater, before we wait for a continue response
        // private static int  DefaultRequireWaitForContinueSize = 2048; // bytes
 
#if HTTP_HEADER_EXTENSIONS_SUPPORTED
        // extension list for our namespace, used as counter, to pull a unque number out 
        private int                     _NextExtension = 10; 
#endif // HTTP_HEADER_EXTENSIONS_SUPPORTED
 

        //
        // Properties
        // 

        internal TimerThread.Timer RequestTimer 
        { 
            get
            { 
                return _Timer;
            }
        }
 
        internal bool Aborted {
            get { 
                return m_Aborted != 0; 
            }
        } 


        /// 
        ///     
        ///       Enables or disables automatically following redirection responses.
        ///     
        ///  
        public bool AllowAutoRedirect {
            get { 
                return (_Booleans&Booleans.AllowAutoRedirect)!=0;
            }
            set {
                if (value) { 
                    _Booleans |= Booleans.AllowAutoRedirect;
                } 
                else { 
                    _Booleans &= ~Booleans.AllowAutoRedirect;
                } 
            }
        }

        ///  
        ///    
        ///       Enables or disables buffering the data stream sent to the server. 
        ///     
        /// 
        public bool AllowWriteStreamBuffering { 
            get {
                return (_Booleans&Booleans.AllowWriteStreamBuffering)!=0;
            }
            set { 
                if (value) {
                    _Booleans |= Booleans.AllowWriteStreamBuffering; 
                } 
                else {
                    _Booleans &= ~Booleans.AllowWriteStreamBuffering; 
                }
            }
        }
 
        private bool ExpectContinue {
            get { 
                return (_Booleans&Booleans.ExpectContinue)!=0; 
            }
            set { 
                if (value) {
                    _Booleans |= Booleans.ExpectContinue;
                }
                else { 
                    _Booleans &= ~Booleans.ExpectContinue;
                } 
            } 
        }
 
        /// 
        ///    
        ///       Returns  if a response has been received from the
        ///       server. 
        ///    
        ///  
        public bool HaveResponse { 
            get {
                return _ReadAResult != null && _ReadAResult.InternalPeekCompleted; 
            }
        }

        // this overrides the public KeepAlive setting. 
        // we use this override for NTLM only
        internal bool NtlmKeepAlive { 
            get { 
                return m_NtlmKeepAlive;
            } 
            set {
                m_NtlmKeepAlive = value;
            }
        } 

 
 
        internal bool SawInitialResponse {
            get { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SawInitialResponse_get() :" + m_SawInitialResponse);
                return m_SawInitialResponse;
            }
            set { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SawInitialResponse_set() :" + value);
                m_SawInitialResponse = value; 
            } 
        }
 
        internal bool BodyStarted {
            get {
                return m_BodyStarted;
            } 
        }
 
        /* 
            Accessor:   KeepAlive
 
            To the app, this means "I want to use a persistent connection if
            available" if set to true, or "I don't want to use a persistent
            connection", if set to false.
 
            This accessor allows the application simply to register its
            desires so far as persistence is concerned. We will act on this 
            and the pipelined requirement (below) at the point that we come 
            to choose or create a connection on the application's behalf
 
            Read:       returns the sense of the keep-alive request switch

            Write:      set the sense of the keep-alive request switch
        */ 

        ///  
        ///     
        ///       Gets or sets the value of the Keep-Alive header.
        ///     
        /// 
        public bool KeepAlive {
            get {
                return m_KeepAlive; 
            }
            set { 
                m_KeepAlive = value; 
            }
        } 

        //
        // LockConnection - set to true when the
        //  request needs exclusive access to the Connection 
        //
        internal bool LockConnection { 
            get { 
                return m_LockConnection;
            } 
            set {
                m_LockConnection = value;
            }
        } 

 
        /* 
            Accessor:   Pipelined
 
            To the app, this means "I want to use pipelining if available" if
            set to true, or "I don't want to use pipelining", if set to false.
            We could infer the state of the keep-alive flag from this setting
            too, but we will decide that only at connection-initiation time. 
            If the application sets pipelining but resets keep-alive then we
            will generate a non-pipelined, non-keep-alive request 
 
            Read:       returns the sense of the pipelined request switch
 
            Write:      sets the sense of the pipelined request switch
        */

        ///  
        ///    
        ///       Gets or sets the value of Pipelined property. 
        ///     
        /// 
        public bool Pipelined { 
            get {
                return m_Pipelined;
            }
            set { 
                m_Pipelined = value;
            } 
        } 

        ///  
        ///    
        ///       Enables or disables pre-authentication.
        ///    
        ///  
        public override bool PreAuthenticate {
            get { 
                return m_PreAuthenticate; 
            }
            set { 
                m_PreAuthenticate = value;
            }
        }
 
        private bool ProxySet {
            get { 
                return (_Booleans&Booleans.ProxySet)!=0; 
            }
            set { 
                if (value) {
                    _Booleans |= Booleans.ProxySet;
                }
                else { 
                    _Booleans &= ~Booleans.ProxySet;
                } 
            } 
        }
 
        private bool RequestSubmitted {
            get {
                return m_RequestSubmitted;
            } 
        }
 
        // Call under lock. 
        private bool SetRequestSubmitted()
        { 
            bool ret = RequestSubmitted;
            m_RequestSubmitted = true;
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitted() returning:" + ret.ToString());
            return ret; 
        }
 
 
        //
        // if the 100 Continue comes in around 350ms there might be race conditions 
        // that make us set Understands100Continue to true when parsing the 100 response
        // in the Connection object and later make us set it to false if the
        // thread that is waiting comes in later than 350ms. to solve this we save info
        // on wether we did actually see the 100 continue. In that case, even if there's a 
        // timeout, we won't set it to false.
        // 
        internal bool Saw100Continue { 
            get {
                return m_Saw100Continue; 
            }
            set {
                m_Saw100Continue = value;
            } 
        }
 
        ///  
        ///    Allows hi-speed NTLM connection sharing with keep-alive
        ///  
        public bool UnsafeAuthenticatedConnectionSharing {
            get {
                return (_Booleans&Booleans.UnsafeAuthenticatedConnectionSharing)!=0;
            } 
            set {
                ExceptionHelper.WebPermissionUnrestricted.Demand(); 
                if (value) { 
                    _Booleans |= Booleans.UnsafeAuthenticatedConnectionSharing;
                } 
                else {
                    _Booleans &= ~Booleans.UnsafeAuthenticatedConnectionSharing;
                }
            } 
        }
        // 
        // When authenticating TO THE proxy we create a shared connection 
        //
        internal  bool UnsafeOrProxyAuthenticatedConnectionSharing { 
            get {
                return m_IsCurrentAuthenticationStateProxy || UnsafeAuthenticatedConnectionSharing;
            }
        } 

 
        // HTTP version of the request 
        private bool IsVersionHttp10 {
            get { 
                return (_Booleans&Booleans.IsVersionHttp10)!=0;
            }
            set {
                if (value) { 
                    _Booleans |= Booleans.IsVersionHttp10;
                } 
                else { 
                    _Booleans &= ~Booleans.IsVersionHttp10;
                } 
            }
        }

        // 
        // SendChunked - set/gets the state of chunk transfer send mode,
        //  if true, we will attempt to upload/write bits using chunked property 
        // 

        ///  
        ///    
        ///       Enable and disable sending chunked data to the server.
        ///    
        ///  
        public bool SendChunked {
            get { 
                return (_Booleans&Booleans.SendChunked)!=0; 
            }
            set { 
                if (RequestSubmitted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
                }
                if (value) { 
                    _Booleans |= Booleans.SendChunked;
                } 
                else { 
                    _Booleans &= ~Booleans.SendChunked;
                } 
            }
        }

        public DecompressionMethods AutomaticDecompression { 
            get {
                return m_AutomaticDecompression; 
            } 
            set {
                if (RequestSubmitted) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
                }
                m_AutomaticDecompression = value;
            } 
        }
 
 
        /*
        // Consider removing. 
        //the headers should already be set at this point
        internal DecompressionMethods DecompressionMethod{
            get{
                DecompressionMethods method = DecompressionMethods.None; 

                string acceptEncoding = Headers[HttpKnownHeaderNames.AcceptEncoding]; 
                if (acceptEncoding != null){ 
                    if((AutomaticDecompression & DecompressionMethods.GZip) != 0){
                        method = DecompressionMethods.GZip; 
                    }
                    //was it set directly?
                    else if(acceptEncoding.IndexOf(HttpWebRequest.GZipHeader) != -1) {
                        method=DecompressionMethods.GZip; 
                    }
                    if (acceptEncoding.IndexOf(HttpWebRequest.DeflateHeader) != -1){ 
                        method |= DecompressionMethods.Deflate; 
                    }
                } 
                return method;
            }
         }
         */ 

 
        // This property holds our actual behaviour. 
        // In some cases we might have to disable chunking even if the user has requested it.
        // In this case SendChunked returns true, but HttpWriteMode is != HttpWriteMode.Chunked 
        internal HttpWriteMode HttpWriteMode {
            get {
                return _HttpWriteMode;
            } 
            set {
                _HttpWriteMode = value; 
            } 
        }
 

        internal string AuthHeader(HttpResponseHeader header) {
            if (_HttpResponse==null) {
                return null; 
            }
#if FEATURE_PAL // ROTORTODO: Remove this after re-enabling methods and op-overloads 
                //            currently if'd out in HttpWebRequest.cs 
            return _HttpResponse.Headers[(int)header];
#else 
            return _HttpResponse.Headers[header];
#endif // FEATURE_PAL
        }
 
        // This is a shortcut that would set the default policy for HTTP/HTTPS.
        // The default policy is overridden by any prefix-registered policy. 
        // Will demand permission for set{} 
        public static new RequestCachePolicy DefaultCachePolicy {
            get { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif
                RequestCachePolicy policy = RequestCacheManager.GetBinding(Uri.UriSchemeHttp).Policy; 
                if (policy == null)
                    return WebRequest.DefaultCachePolicy; 
                return policy; 
#if DEBUG
                } 
#endif
            }
            set {
#if DEBUG 
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif 
                // This is a replacement of RequestCachePermission demand since we are not including the latest in the product. 
                ExceptionHelper.WebPermissionUnrestricted.Demand();
 
                RequestCacheBinding binding = RequestCacheManager.GetBinding(Uri.UriSchemeHttp);
                RequestCacheManager.SetBinding(Uri.UriSchemeHttp, new RequestCacheBinding(binding.Cache, binding.Validator, value));
#if DEBUG
                } 
#endif
            } 
        } 

        ///  
        ///    
        ///       Gets or sets the default for the MaximumResponseHeadersLength property.
        ///    
        ///     
        ///       This value can be set in the config file, the default can be overridden using the MaximumResponseHeadersLength property.
        ///     
        ///  
        public static int DefaultMaximumResponseHeadersLength {
            get { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif
                return SettingsSectionInternal.Section.MaximumResponseHeadersLength; 
#if DEBUG
                } 
#endif 
            }
            set { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif
                ExceptionHelper.WebPermissionUnrestricted.Demand(); 
                if (value<0 && value!=-1) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall)); 
                } 
                SettingsSectionInternal.Section.MaximumResponseHeadersLength = value;
#if DEBUG 
                }
#endif
            }
        } 

        public static int DefaultMaximumErrorResponseLength { 
            get { 
                return SettingsSectionInternal.Section.MaximumErrorResponseLength;
            } 
            set {
                ExceptionHelper.WebPermissionUnrestricted.Demand();
                if (value<0 && value!=-1) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall)); 
                }
                SettingsSectionInternal.Section.MaximumErrorResponseLength = value; 
            } 
        }
 
        /// 
        ///    
        ///       Gets or sets the maximum allowed length of the response headers.
        ///     
        ///    
        ///       The length is measured in kilobytes (1024 bytes) and it includes the response status line and the response 
        ///       headers as well as all extra control characters received as part of the HTTP protocol. A value of -1 means 
        ///       no such limit will be imposed on the response headers, a value of 0 means that all requests will fail.
        ///     
        /// 
        public int MaximumResponseHeadersLength {
            get {
                return _MaximumResponseHeadersLength; 
            }
            set { 
                if (RequestSubmitted) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                if (value<0 && value!=-1) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall));
                }
                _MaximumResponseHeadersLength = value; 
            }
        } 
 
        //
        // AbortDelegate - set by ConnectionGroup when 
        //  the request is blocked waiting for a Connection
        //
        internal HttpAbortDelegate AbortDelegate {
            set { 
                _AbortDelegate = value;
            } 
        } 

        // This is invoked by the Connection whenever we get access to Write to the Connection 
        internal LazyAsyncResult ConnectionAsyncResult {
            get {
                return _ConnectionAResult;
            } 
        }
 
        // This is invoked by the Connection whenever we get to Read from the Connection 
        internal LazyAsyncResult ConnectionReaderAsyncResult {
            get { 
                return _ConnectionReaderAResult;
            }
        }
 
        // True, if the EndGetRequestStream or GetRequestStream call returned
        // codereview: Used ONLY by Sync code 
        private bool UserRetrievedWriteStream { 
            get {
                return _WriteAResult != null && _WriteAResult.InternalPeekCompleted; 
            }
        }

        // True if we're being used in an async manner 
        internal bool Async {
            get { 
                // So Long as we've not been set to false, we operate as an async request 
                return _RequestIsAsync!=TriState.False;
            } 
            set {
                if (_RequestIsAsync == TriState.Unspecified) {
                    _RequestIsAsync = value ? TriState.True : TriState.False;
                } 
            }
        } 
 
        //
        // UnlockConnectionDelegate - set by the Connection 
        //  iff the Request is asking for exclusive access (ie LockConnection == true)
        //  in this case UnlockConnectionDelegate must be called when the Request
        //  has finished authentication.
        // 
        internal UnlockConnectionDelegate UnlockConnectionDelegate {
            get { 
                return _UnlockDelegate; 
            }
            set { 
                _UnlockDelegate = value;
            }
        }
 
        private bool UsesProxy {
            get { 
                return ServicePoint.InternalProxyServicePoint; 
            }
        } 

        internal HttpStatusCode ResponseStatusCode {
            get {
                return _HttpResponse.StatusCode; 
            }
        } 
 
        internal bool UsesProxySemantics {
            get { 
                return ServicePoint.InternalProxyServicePoint && (((object)_Uri.Scheme != (object)Uri.UriSchemeHttps) || (IsTunnelRequest));
            }
        }
 
        internal Uri ChallengedUri {
            get { 
                return CurrentAuthenticationState.ChallengedUri; 
            }
        } 

        internal AuthenticationState ProxyAuthenticationState {
            get {
                if (_ProxyAuthenticationState==null) { 
                    _ProxyAuthenticationState = new AuthenticationState(true);
                } 
                return _ProxyAuthenticationState; 
            }
        } 

        internal AuthenticationState ServerAuthenticationState {
            get {
                if (_ServerAuthenticationState==null) { 
                    _ServerAuthenticationState = new AuthenticationState(false);
                } 
                return _ServerAuthenticationState; 
            }
            set { 
                _ServerAuthenticationState = value;
            }
        }
 
        // the AuthenticationState we're using for authentication (proxy/server)
        // used to match entries in the Hashtable in NtlmClient & NegotiateClient 
        internal AuthenticationState CurrentAuthenticationState { 
            get {
                return m_IsCurrentAuthenticationStateProxy ? _ProxyAuthenticationState : _ServerAuthenticationState; 
            }
            set {
                m_IsCurrentAuthenticationStateProxy = (object)_ProxyAuthenticationState==(object)value;
            } 
        }
 
#if !FEATURE_PAL 
        //
        // ClientCertificates - sets our certs for our reqest, 
        //  uses a hash of the collection to create a private connection
        //  group, to prevent us from using the same Connection as
        //  non-Client Authenticated requests.
        // 
        public X509CertificateCollection ClientCertificates {
            get { 
                if (_ClientCertificates==null) { 
                    _ClientCertificates = new X509CertificateCollection();
                } 
                return _ClientCertificates;
            }
            set {
                if (value==null) { 
                    throw new ArgumentNullException("value");
                } 
                _ClientCertificates = value; 
            }
        } 

#endif // !FEATURE_PAL

        ///  
        ///    [To be supplied.]
        ///  
        public CookieContainer CookieContainer { 
            get {
                return _CookieContainer; 
            }
            set {
                _CookieContainer = value;
            } 
        }
 
        ///  
        ///    
        ///       Gets the original Uri of the request. 
        ///       This read-only propery returns the Uri for this request. The
        ///       Uri object was created by the constructor and is always non-null.
        ///
        ///       Note that it will always be the base Uri, and any redirects, 
        ///       or such will not be indicated.
        ///     
        ///  
        public override Uri RequestUri {                                   // read-only
            get { 
                return _OriginUri;
            }
        }
 
        /*
            Accessor:   ContentLength 
 
            The property that controls the Content-Length of the request entity
            body. Getting this property returns the last value set, or -1 if 
            no value has been set. Setting it sets the content length, and
            the application must write that much data to the stream.
            Setting this property has a side effect on InternalSendChunked, it sets it to false.
 
            Input:
                Content length 
 
            Returns: The value of the content length on get.
 
        */

        /// 
        ///     
        ///       Gets or sets the Content-Length header of the request.
        ///     
        ///  
        public override long ContentLength {
            get { 
                return _ContentLength;
            }
            set {
                if (RequestSubmitted) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
                } 
                if (value < 0) { 
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_clsmall));
                } 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ContentLength_set() was:" + _ContentLength + " now:" + value);
                _ContentLength = value;
            }
        } 

        ///  
        ///    Timeout is set to 100 seconds by default 
        /// 
        public override int Timeout { 
            get {
                return _Timeout;
            }
            set { 
                if (value<0 && value!=System.Threading.Timeout.Infinite) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_io_timeout_use_ge_zero)); 
                } 
                if (_Timeout != value)
                { 
                    _Timeout = value;
                    _TimerQueue = null;
                }
            } 
        }
 
        private TimerThread.Queue TimerQueue 
        {
            get 
            {
                TimerThread.Queue queue = _TimerQueue;
                if (queue == null)
                { 
                    queue = TimerThread.GetOrCreateQueue(_Timeout == 0 ? 1 : _Timeout);
                    _TimerQueue = queue; 
                } 
                return queue;
            } 
        }

        /// 
        ///    Used to control the Timeout when calling Stream.Read (AND) Stream.Write. 
        ///         Effects Streams returned from GetResponse().GetResponseStream() (AND) GetRequestStream().
        ///         Default is 5 mins. 
        ///     
        /// 
        public int ReadWriteTimeout { 
            get {
                return _ReadWriteTimeout;
            }
            set { 
                if (RequestSubmitted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                if (value<=0 && value!=System.Threading.Timeout.Infinite) {
                    throw new ArgumentOutOfRangeException(SR.GetString(SR.net_io_timeout_use_gt_zero)); 
                }
                _ReadWriteTimeout = value;
            }
        } 

 
        internal long SwitchToContentLength() { 
            //prevents clearing of transferencoding if we can't resubmit.
            if(HaveResponse) 
            {
                return -1;
            }
 

            //we should only switch to content length if the server is unknown of less than IIS6.0 
            //we only do this if it was orginially chunked.  If it was bufferonly, we should allow the switch 
            if( HttpWriteMode == HttpWriteMode.Chunked){
                ConnectStream stream = _OldSubmitWriteStream; 
                if(stream == null){
                    stream = _SubmitWriteStream;
                }
                if(stream.Connection != null && stream.Connection.IISVersion >= 6){ 
                    return -1;
                } 
            } 

            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SwitchToContentLength() Switching to HttpWriteMode.ContentLength from:" + HttpWriteMode.ToString()); 

            long returnValue = -1;
            long oldContentLength = _ContentLength;
 
            if (HttpWriteMode != HttpWriteMode.None){
 
                if(HttpWriteMode == HttpWriteMode.Buffer){ 
                    _ContentLength = _SubmitWriteStream.BufferedData.Length;
                    m_OriginallyBuffered = true; 
                    HttpWriteMode = HttpWriteMode.ContentLength;
                    return -1;
                }
 
                //1st ntlm leg w/ preauthenticated connection
                // we don't have data yet 
                if (NtlmKeepAlive && _OldSubmitWriteStream == null) { 
                    _ContentLength = 0;
                    _SubmitWriteStream.SuppressWrite = true; 

                    //if this was previously a bufferonly request, we won't set the contentlength
                    //back after header serialization
                    if(_SubmitWriteStream.BufferOnly != true) 
                    {
                        returnValue = oldContentLength; 
                    } 

                    if(HttpWriteMode == HttpWriteMode.Chunked){ 
                        HttpWriteMode = HttpWriteMode.ContentLength;
                        _SubmitWriteStream.SwitchToContentLength();
                        //restore request settings after headers are serialized
                        returnValue = -2; 
                        _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding);
                    } 
                } 

                //this is a resubmit w/ data already available 
                if(_OldSubmitWriteStream != null){
                    //first ntlm leg after noauth
                    if(NtlmKeepAlive){
                        _ContentLength = 0; 
                    }
                    //2nd leg of ntlm, or resubmit for chunked on  -1){ 
                _ContentLength = value;
            } 
            if(value == -2){
                _ContentLength = -1;
                HttpWriteMode = HttpWriteMode.Chunked;
            } 
        }
 
        ///  
        ///    
        ///     Removes the ConnectionGroup and the Connection resources 
        ///     held open usually do to NTLM operations.
        ///     
        /// 
        private void ClearAuthenticatedConnectionResources() { 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearAuthenticatedConnectionResources()");
 
            if (ProxyAuthenticationState.UniqueGroupId != null || ServerAuthenticationState.UniqueGroupId != null) 
            {
                GlobalLog.Assert(!UnsafeAuthenticatedConnectionSharing, "Created a unique connection AND UnsafeConnectionNtlmAuthentication is true."); 
                // A unique connection was create so we must tear it down or it gets leaked
                ServicePoint.ReleaseConnectionGroup(GetConnectionGroupLine());
            }
 
            UnlockConnectionDelegate unlockConnectionDelegate = this.UnlockConnectionDelegate;
            try { 
                if (unlockConnectionDelegate != null) { 
                    unlockConnectionDelegate();
                } 
                this.UnlockConnectionDelegate = null;
            }
            catch (Exception exception) {
                if (NclUtilities.IsFatal(exception)) throw; 
            }
            catch { 
            } 

            ProxyAuthenticationState.ClearSession(this); 
            ServerAuthenticationState.ClearSession(this);
        }

        // 
        // Is set to true under the _connection_ lock to indicate that header are written
        // Is set to false when we start submitting 
        // 
        internal bool HeadersCompleted {
            get { 
                return m_HeadersCompleted;
            }
            set {
                m_HeadersCompleted = value; 
            }
        } 
 
        // This method checks the consistency of the protocol usage.
        // It also might adjust the upload behaviour to comply with what the server supports. 
        private void CheckProtocol(bool onRequestStream) {
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckProtocol(" + onRequestStream + ") HttpWriteMode:" + HttpWriteMode + " SendChunked:" + SendChunked + " ContentLength:" + ContentLength);
            if (!CanGetRequestStream) {
                if (onRequestStream) { 
                    // prevent someone from getting a request stream, if the protocol verb/method doesn't support it
                    throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget)); 
                } 
                else {
                    // prevent someone from setting ContentLength/Chunked, and then doing a Get 
                    if (HttpWriteMode!=HttpWriteMode.Unknown && HttpWriteMode!=HttpWriteMode.None) {
                        throw new ProtocolViolationException(SR.GetString(SR.net_nocontentlengthonget));
                    }
                    // GET & HEAD requests will end up here 
                    HttpWriteMode = HttpWriteMode.None;
                } 
            } 
            else {
                if (HttpWriteMode==HttpWriteMode.Unknown) { 
                    if (SendChunked) {
                        // prevent someone from sending chunked to a HTTP/1.0 server
                        if (ServicePoint.HttpBehaviour==HttpBehaviour.HTTP11 || ServicePoint.HttpBehaviour==HttpBehaviour.Unknown) {
                            HttpWriteMode = HttpWriteMode.Chunked; 
                        }
                        else { 
                            if (AllowWriteStreamBuffering) { 
                                // change this request to buffer instead of using chunking
                                HttpWriteMode = HttpWriteMode.Buffer; 
                            }
                            else {
                                throw new ProtocolViolationException(SR.GetString(SR.net_nochunkuploadonhttp10));
                            } 
                        }
                    } 
                    else { 
                        // we need to do some fixups if we don't have a HttpWriteMode
                        // unknown verbs (like TRACE) will also end up here. since we don't know if we need to send 
                        // a content we'll assume we won't and upload will work only if ContentLength or Chunked
                        // were set. note that this means that we won't ever buffer for unknown verbs unless
                        // you call [Begin]GetRequestStream before [Begin]GetResponse.
                        HttpWriteMode = ContentLength>=0 ? HttpWriteMode.ContentLength : onRequestStream ? HttpWriteMode.Buffer : HttpWriteMode.None; 
                    }
                } 
            } 
            if (HttpWriteMode!=HttpWriteMode.Chunked) {
                if (onRequestStream && ContentLength==-1 && !AllowWriteStreamBuffering && KeepAlive) { 
                    // Missing Entity Body Delimiter:
                    // prevent someone from trying to send data without setting
                    // a ContentLength or InternalSendChunked when buffering is disabled and on a KeepAlive connection
                    throw new ProtocolViolationException(SR.GetString(SR.net_contentlengthmissing)); 
                }
                if (!ValidationHelper.IsBlankString(TransferEncoding)) { 
                    // Transfer Encoding Without Chunked 
                    // prevent someone from setting a Transfer Encoding without having InternalSendChunked==true
                    throw new InvalidOperationException(SR.GetString(SR.net_needchunked)); 
                }
            }
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckProtocol(" + onRequestStream + ") no error, returning null. HttpWriteMode:" + HttpWriteMode + " SendChunked:" + SendChunked + " ContentLength:" + ContentLength);
            return; 
        }
 
 
        /// 
        ///     
        ///    Retreives the Request Stream from an HTTP Request uses an Async
        ///      operation to do this, and the result is retrived async.
        ///
        ///    Async operations include work in progess, this call is used to retrieve 
        ///    results by pushing the async operations to async worker thread on the callback.
        ///    There are many open issues involved here including the handling of possible blocking 
        ///    within the bounds of the async worker thread or the case of Write and Read stream 
        ///    operations still blocking.
        ///    
        /// 
        [HostProtection(ExternalThreading=true)]
        public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) {
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream"); 
            if(Logging.On)Logging.Enter(Logging.Web, this, "BeginGetRequestStream", "");
 
            CheckProtocol(true);

#if !FEATURE_PAL
            ContextAwareResult asyncResult = new ContextAwareResult(IdentityRequired, true, this, state, callback); 
#else // !FEATURE_PAL
            ContextAwareResult asyncResult = new ContextAwareResult(false, true, this, state, callback); 
#endif // !FEATURE_PAL 

 
            lock (asyncResult.StartPostingAsyncOp())
            {
                // and have a result (weird but was supported in V1.X as repeated calls for the submit stream.
                if (_WriteAResult != null && _WriteAResult.InternalPeekCompleted) 
                {
                    if (_WriteAResult.Result is Exception) 
                    { 
                        throw (Exception)_WriteAResult.Result;
                    } 

                    try
                    {
                        asyncResult.InvokeCallback(_WriteAResult.Result); 
                    }
                    catch (Exception e) 
                    { 
                        Abort(e, AbortState.Public);
                        throw; 
                    }
                }
                else
                { 
                    // prevent new requests when low on resources
                    if (!RequestSubmitted && NclUtilities.IsThreadPoolLow()) 
                    { 
                        Exception exception = new InvalidOperationException(SR.GetString(SR.net_needmorethreads));
                        Abort(exception, AbortState.Public); 
                        throw exception;
                    }

                    lock(this) 
                    {
                        if (_WriteAResult != null) 
                        { 
                            throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                        } 

                        // See if we're already submitted a request (e.g. via GetResponse).
                        if (SetRequestSubmitted())
                        { 
                            // Not completed write stream, this is an application error.
                            throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                        } 

                        // If there's already been a _ReadAResult completed, it better have been with an exception, like an abort. 
                        // We need to check within this lock.  Before the lock, _WriteAResult didn't exist so won't have been notified.
                        // BeginSubmitRequest() will fail silently if we go ahead and call it after an abort.  Since we know this is the
                        // first call to any of the [Begin]GetRe... methods by the above checks, we know ProcessResponse can't have been
                        // called or any other valid _ReadAResult created yet. 
                        if (_ReadAResult != null)
                        { 
                            GlobalLog.Assert(_ReadAResult.InternalPeekCompleted, "HttpWebRequest#{0}::BeginGetRequestStream()|Incomplete _ReadAResult present on request.", ValidationHelper.HashString(this)); 
                            GlobalLog.Assert(_ReadAResult.Result is Exception, "HttpWebRequest#{0}::BeginGetRequestStream()|_ReadAResult with successful completion already present on request.", ValidationHelper.HashString(this));
                            throw (Exception) _ReadAResult.Result; 
                        }

                        // get async going
                        _WriteAResult = asyncResult; 
                        Async = true;
                    } 
 
                    // OK, we haven't submitted the request yet, so do so now
                    // save off verb from origin Verb 
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream() resetting CurrentMethod to " + _OriginVerb);
                    CurrentMethod = _OriginVerb;
                    BeginSubmitRequest();
                } 

                asyncResult.FinishPostingAsyncOp(); 
            } 

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream", ValidationHelper.HashString(asyncResult)); 
            if(Logging.On)Logging.Exit(Logging.Web, this, "BeginGetRequestStream", asyncResult);
            return asyncResult;
#if DEBUG
            } 
#endif
        } 
 
        /// 
        ///  Retreives the Request Stream after an Async operation has completed  
        /// 
        public override Stream EndGetRequestStream(IAsyncResult asyncResult) {
#if DEBUG
            using (GlobalLog.SetThreadKind(ThreadKinds.User)) { 
#endif
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream", ValidationHelper.HashString(asyncResult)); 
            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetRequestStream", ""); 

            // 
            // parameter validation
            //
            if (asyncResult == null) {
                throw new ArgumentNullException("asyncResult"); 
            }
            LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult; 
            if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) { 
                throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
            } 
            if (castedAsyncResult.EndCalled) {
                throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetRequestStream"));
            }
 
            ConnectStream connectStream = castedAsyncResult.InternalWaitForCompletion() as ConnectStream;
            castedAsyncResult.EndCalled = true; 
 
            if (connectStream == null)
            { 
                if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetRequestStream", castedAsyncResult.Result as Exception);
                throw (Exception) castedAsyncResult.Result;
            }
 
            // Otherwise it worked, so return the HttpWebResponse.
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream", ValidationHelper.HashString(connectStream)); 
            if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetRequestStream", connectStream); 
            return connectStream;
#if DEBUG 
            }
#endif
        }
 
        /// 
        /// Gets a  that the application can use to write request data. 
        ///    This property returns a stream that the calling application can write on. 
        ///    This property is not settable.  Getting this property may cause the
        ///    request to be sent, if it wasn't already. Getting this property after 
        ///    a request has been sent that doesn't have an entity body causes an
        ///    exception to be thrown.
        ///
        ///  
        public override Stream GetRequestStream() {
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) { 
#endif
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream"); 
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetRequestStream", "");

            CheckProtocol(true);
 
            // See if we're already submitted a request and have a result cached.
            if (_WriteAResult == null || !_WriteAResult.InternalPeekCompleted) 
            { 
                lock(this)
                { 
                    if (_WriteAResult != null)
                    {
                        throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                    } 

                    // See if we're already submitted a request (e.g. via GetResponse). 
                    if (SetRequestSubmitted()) 
                    {
                        // Not completed write stream, this is an application error. 
                        throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                    }

                    // If there's already been a _ReadAResult completed, it better have been with an exception, like an abort. 
                    // We need to check within this lock.  Before the lock, _WriteAResult didn't exist so won't have been notified.
                    // BeginSubmitRequest() will fail silently if we go ahead and call it after an abort.  Since we know this is the 
                    // first call to any of the [Begin]GetRe... methods by the above checks, we know ProcessResponse can't have been 
                    // called or any other valid _ReadAResult created yet.
                    if (_ReadAResult != null) 
                    {
                        GlobalLog.Assert(_ReadAResult.InternalPeekCompleted, "HttpWebRequest#{0}::GetRequestStream()|Incomplete _ReadAResult present on request.", ValidationHelper.HashString(this));
                        GlobalLog.Assert(_ReadAResult.Result is Exception, "HttpWebRequest#{0}::GetRequestStream()|_ReadAResult with successful completion already present on request.", ValidationHelper.HashString(this));
                        throw (Exception) _ReadAResult.Result; 
                    }
 
                    // use the AsyncResult to return our Stream 
                    _WriteAResult = new LazyAsyncResult(this, null, null);
                    Async = false; 
                }

                // OK, we haven't submitted the request yet, so do so now
                // save off verb from origin Verb 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "GetRequestStream() resetting CurrentMethod to " + _OriginVerb);
                CurrentMethod = _OriginVerb; 
 
                // Submit the Request, causes us to queue ourselves to a Connection and may block
                // It has happened that Sync path uses this loop the Retry memeber for handling resubmissions. 
                while (m_Retry && !_WriteAResult.InternalPeekCompleted) {
                    _OldSubmitWriteStream = null;
                    _SubmitWriteStream = null;
                    BeginSubmitRequest(); 
                }
 
                while(Aborted && !_WriteAResult.InternalPeekCompleted) 
                {
                    // spin untill the _CoreResponse is set 
                    if (!(_CoreResponse is Exception))
                        Thread.SpinWait(1);
                    else
                        CheckWriteSideResponseProcessing(); 
                }
            } 
 
            ConnectStream connectStream = _WriteAResult.InternalWaitForCompletion() as ConnectStream;
            _WriteAResult.EndCalled = true; 
            if (connectStream == null)
            {
                if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetRequestStream", _WriteAResult.Result as Exception);
                throw (Exception) _WriteAResult.Result; 
            }
 
            if(Logging.On)Logging.Exit(Logging.Web, this, "GetRequestStream", connectStream); 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream", ValidationHelper.HashString(connectStream));
            return connectStream; 
#if DEBUG
            }
#endif
        } 

 
        // 
        // This read-only propery does a test against the object to verify that
        // we're not sending data with a GET or HEAD, these are dissallowed by the HTTP spec. 
        // Returns: true if we allow sending data for this request, false otherwise
        //
        private bool CanGetRequestStream {
            get { 
                bool result = !CurrentMethod.ContentBodyNotAllowed;
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CanGetRequestStream(" + _OriginVerb + "): " + result); 
                return result; 
            }
        } 

        //
        // This read-only propery does a test against the object to verify if
        // we're allowed to get a Response Stream to read, 
        // this is dissallowed per the HTTP spec for a HEAD request.
        // Returns: true if we allow sending data for this request, false otherwise 
        // 
        internal bool CanGetResponseStream {
            get { 
                bool result = !CurrentMethod.ExpectNoContentResponse;
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CanGetResponseStream(" + CurrentMethod + "): " + result);
                return result;
            } 
        }
 
        // 
        // This read-only propery describes whether we can
        // send this verb without content data. 
        // Assumes Method is already set.
        // Returns: true, if we must send some kind of content
        //
        internal bool RequireBody { 
            get {
                bool result = CurrentMethod.RequireContentBody; 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::RequireBody(" + CurrentMethod + "): " + result); 
                return result;
            } 
        }

        /*++
 
            CheckBuffering - Determine if we need buffering based on having no contentlength
 
 
                consider the case in which we have no entity body delimiters:
                    RequireBody && ContentLength==-1 && !SendChunked == true 

                now we need to consider 3 cases:

                AllowWriteStreamBuffering (1) 
                    - buffer internally all the data written to the request stream when the user
                      closes the request stream send it on the wire with a ContentLength 
 
                !AllowWriteStreamBuffering
                    - can't buffer internally all the data written to the request stream 
                      so the data MUST go to the wire and the server sees it: 2 cases

                    !KeepAlive (2)
                        - send a "Connection: close" header to the server. the server SHOULD 
                          1) send a final response
                          2) read all the data on the connection and treat it as being part of the 
                             entity body of this request. 

                    KeepAlive (3) 
                        - throw, we can't do this, 'cause the server wouldn't know when the data is over.


            Input: 
                    None.
 
            Returns: 
                    true if we need buffering, false otherwise.
 
        --*/

        /*
        // Consider removing. 
        internal bool CheckBuffering {
            // 
            // ContentLength is not set, and user is not chunking, buffering is on 
            // so force the code into writing (give the user a stream to write to)
            // and we'll buffer for him 
            //
            get {
                bool checkBuffering = RequireBody && ContentLength==-1 && HttpWriteMode!=HttpWriteMode.Chunked && AllowWriteStreamBuffering && ServicePoint.HttpBehaviour!=HttpBehaviour.HTTP11;
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckBuffering() returns:" + checkBuffering.ToString()); 
                return checkBuffering;
            } 
        } 
        */
 
        private bool HasEntityBody {
            get {
                return HttpWriteMode==HttpWriteMode.Chunked || HttpWriteMode==HttpWriteMode.Buffer || (HttpWriteMode==HttpWriteMode.ContentLength && ContentLength>0);
            } 
        }
 
 
        // This is a notify from the connection ReadCallback about
        // - error response received and 
        // - the KeepAlive status agreed by both sides
        internal void ErrorStatusCodeNotify(Connection connection, bool isKeepAlive, bool fatal) {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify");
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify() Connection has reported Error Response Status" + (fatal ? " (fatal)" : "")); 
            ConnectStream submitStream = _SubmitWriteStream;
            if (submitStream != null && submitStream.Connection == connection) { 
                if (!fatal) 
                {
                    submitStream.ErrorResponseNotify(isKeepAlive); 
                }
                else
                {
                    if (!Aborted) 
                    {
                        submitStream.FatalResponseNotify(); 
                    } 
                }
            } 
            else {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify() IGNORE connection is not used");
            }
        } 

        /* 
            Method: DoSubmitRequestProcessing 

            Does internal processing of redirect and request retries for authentication 
            Assumes that it cannot block, this returns a state var indicating when it
            needs to block

            Assumes that we are never called with a null response 

            Input: 
                none 

            Returns: 
                HttpProcessingResult -

        */
 
        //
        // ASSUMPTION: If this method throws the exception must be caught and handled 
        // appropriatelly by the caller. 
        //
        private HttpProcessingResult DoSubmitRequestProcessing(ref Exception exception) 
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing");
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify");
            HttpProcessingResult result = HttpProcessingResult.Continue; 

            m_Retry = false; 
 
            try
            { 
                //
                // We have a response of some sort, see if we need to resubmit
                // it do to authentication, redirection or something
                // else, then handle clearing out state and draining out old response. 
                //
                if (_HttpResponse != null) { 
                    // give apps the chance to examine the headers of the new response 
                    if (_CookieContainer != null) {
                        CookieModule.OnReceivedHeaders(this); 
                    }

                    ProxyAuthenticationState.Update(this);
                    ServerAuthenticationState.Update(this); 
                }
 
                bool resubmit = false; 
                bool checkNextProxy = true;
                if (_HttpResponse == null) 
                {
                    resubmit = true;
                }
                else if (CheckResubmitForCache(ref exception) || CheckResubmit(ref exception)) 
                {
                    resubmit = true; 
                    checkNextProxy = false; 
                }
 
                // See if we're doing proxy failover.  If so, see if there's another one.
                //

                ServicePoint servicePoint = null; 
                if (checkNextProxy)
                { 
                    WebException webException = exception as WebException; 
                    if (webException != null && webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal)
                    { 
                        ProxyChain chain = _ProxyChain;
                        if (chain != null)
                        {
                            servicePoint = ServicePointManager.FindServicePoint(chain); 
                        }
                        resubmit = servicePoint != null; 
                    } 
                }
 
                if (resubmit)
                {
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing() resubmiting this request.");
 
                    // Here is a little hack for sync looping through BeginSubmitRequest.
                    // We want to unlock cache protocol only if this is NOT a retry. 
                    if (CacheProtocol != null && _HttpResponse != null) 
                        CacheProtocol.Reset();
 
                    ClearRequestForResubmit();

                    // In these cases, we don't know whether to keep the credentials for the follow-up request or not.
                    // Different auth schemes have different requirements.  The typical case is to keep them - NTLM 
                    // requires this path in order to work at all.  But Kerberos for example can give a 401 here.
                    // Set a flag saying that if we get a 401, start over without credentials. 
                    WebException e = exception as WebException; 
                    if(e != null){
                        if (e.Status == WebExceptionStatus.PipelineFailure || e.Status == WebExceptionStatus.KeepAliveFailure) { 
                            m_Extra401Retry = true;
                        }
                    }
 
                    if (servicePoint == null)
                    { 
                        servicePoint = FindServicePoint(true); 
                    }
                    else 
                    {
                        _ServicePoint = servicePoint;
                    }
 
                    if (Async) {
                        SubmitRequest(servicePoint); 
                    } 
                    else {
                        // under sync conditions, we let GetResponse() loop calling BeginSubmitRequest() until we're done 
                        m_Retry = true;
                    }
                    result = HttpProcessingResult.WriteWait;
                } 
            }
            finally 
            { 
                if (result == HttpProcessingResult.Continue)
                { 
                    ClearAuthenticatedConnectionResources();
                }
            }
 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing", result.ToString());
            return result; 
        } 

 

        /// 
        ///    Used to query for the Response of an HTTP Request using Async
        ///  
        [HostProtection(ExternalThreading=true)]
        public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) { 
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse");
            if(Logging.On)Logging.Enter(Logging.Web, this, "BeginGetResponse", "");

            CheckProtocol(false); 

            ConnectStream stream = _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream; 
 
            // Close the request stream if the user forgot to do that and all data is written.
            if(stream != null && !stream.IsClosed && stream.BytesLeftToWrite == 0) 
            {
                stream.Close();
            }
 
#if !FEATURE_PAL
            ContextAwareResult asyncResult = new ContextAwareResult(IdentityRequired, true, this, state, callback); 
#else // FEATURE_PAL 
            ContextAwareResult asyncResult = new ContextAwareResult(false, true, this, state, callback);
#endif 

            if (!RequestSubmitted && NclUtilities.IsThreadPoolLow())
            {
                // prevent new requests when low on resources 
                Exception exception = new InvalidOperationException(SR.GetString(SR.net_needmorethreads));
                Abort(exception, AbortState.Public); 
                throw exception; 
            }
 
            // Need to lock the context until it's created (if necessary) in Returning().
            lock (asyncResult.StartPostingAsyncOp())
            {
                bool gotResponse = false; 
                bool requestSubmitted;
                lock (this) 
                { 
                    requestSubmitted = SetRequestSubmitted();
 
                    if (HaveResponse)
                    {
                        gotResponse = true;
                    } 
                    else
                    { 
                        if (_ReadAResult != null) 
                        {
                            throw new InvalidOperationException(SR.GetString(SR.net_repcall)); 
                        }

                        _ReadAResult = asyncResult;
                        Async = true; 
                    }
                } 
 
                // Must check this after setting _ReadAResult, which holds the context which may be used for permission checks etc.
                // See if we need to do the call-done processing here. 
                CheckDeferredCallDone(stream);

                if (gotResponse)
                { 
                    if (Logging.On) Logging.Exit(Logging.Web, this, "BeginGetResponse", _ReadAResult.Result);
                    GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse", "Already Completed, response = " + ValidationHelper.HashString(_ReadAResult.Result)); 
                    Exception e = _ReadAResult.Result as Exception; 
                    if (e != null)
                    { 
                        throw e;
                    }

                    try 
                    {
                        asyncResult.InvokeCallback(_ReadAResult.Result); 
                    } 
                    catch (Exception exception)
                    { 
                        Abort(exception, AbortState.Public);
                        throw;
                    }
                } 
                else
                { 
                    // If we're here it's because we don't have the response yet. We may have 
                    // already submitted the request, but if not do so now.
                    if (!requestSubmitted) 
                    {
                        // Save Off verb, and use it to make the request
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + ": resetting CurrentMethod to " + _OriginVerb);
                        CurrentMethod = _OriginVerb; 
                    }
 
                    // If we're here it's because we don't have the response yet. We may have 
                    //  already submitted the request, but if not do so now.
                    if (_RerequestCount > 0 || !requestSubmitted) { 
                        while (m_Retry) {
                            // Keep looping in case there are redirects, auth re-requests, etc
                            BeginSubmitRequest();
                        } 
                    }
                } 
                asyncResult.FinishPostingAsyncOp(); 
            }
 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse", ValidationHelper.HashString(asyncResult));
            if(Logging.On)Logging.Exit(Logging.Web, this, "BeginGetResponse", asyncResult);
            return asyncResult;
#if DEBUG 
            }
#endif 
        } 

        ///  
        ///  Retreives the Response Result from an HTTP Result after an Async operation has completed
        /// 
        public override WebResponse EndGetResponse(IAsyncResult asyncResult) {
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
#endif 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(asyncResult)); 
            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetResponse", "");
 
            //
            // parameter validation
            //
            if (asyncResult==null) { 
                throw new ArgumentNullException("asyncResult");
            } 
 
            LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
            if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) { 
                throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
            }
            if (castedAsyncResult.EndCalled) {
                throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetResponse")); 
            }
 
            HttpWebResponse httpWebResponse = castedAsyncResult.InternalWaitForCompletion() as HttpWebResponse; 
            castedAsyncResult.EndCalled = true;
 
            if (httpWebResponse == null)
            {
                if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetResponse", castedAsyncResult.Result as Exception);
                throw (Exception) castedAsyncResult.Result; 
            }
 
            GlobalLog.Assert(httpWebResponse.ResponseStream != null, "HttpWebRequest#{0}::EndGetResponse()|httpWebResponse.ResponseStream == null", ValidationHelper.HashString(this)); 
            // Otherwise it worked, so return the HttpWebResponse.
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse", ValidationHelper.HashString(httpWebResponse)); 
            if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetResponse", httpWebResponse);
            return httpWebResponse;
#if DEBUG
            } 
#endif
        } 
 
        private void CheckDeferredCallDone(ConnectStream stream)
        { 
            object returnResult = Interlocked.Exchange(ref m_PendingReturnResult, DBNull.Value);
            if (returnResult == NclConstants.Sentinel)
            {
#if DEBUG 
                if (!Async)
                { 
                    using (GlobalLog.SetThreadKind(ThreadKinds.Sync)) { 
                        EndSubmitRequest();
                    } 
                }
                else
#endif
                EndSubmitRequest(); 
            }
            else if (returnResult != null && returnResult != DBNull.Value) 
            { 
                // It could still be Missing.Value, which indicates ProcessWriteCallDone() should be called with null.
                stream.ProcessWriteCallDone(returnResult as ConnectionReturnResult); 
            }
        }

        ///  
        ///    
        ///       Returns a response from a request to an Internet resource. 
        ///    The response property. This property returns the WebResponse for this 
        ///    request. This may require that a request be submitted first.
        /// 
        ///     The idea is that we look and see if a request has already been
        ///    submitted. If one has, we'll just return the existing response
        ///    (if it's not null). If we haven't submitted a request yet, we'll
        ///    do so now, possible multiple times while we handle redirects 
        ///    etc.
        ///     
        ///  
        public override WebResponse GetResponse() {
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
#endif
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse");
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetResponse", ""); 

            CheckProtocol(false); 
 
            // Many of these logics require GetResponse() to be called after all write-stream activity is done.  You can't call it
            // simultaneously on another thread and expect it to block until it can run.  Doing that can cause the request to 
            // hang.

            ConnectStream stream = _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream;
 
            // Close the request stream if the user forgot to do that and all data is written.
            if (stream != null && !stream.IsClosed && stream.BytesLeftToWrite == 0) 
                stream.Close(); 

 
            // return response, if the response is already set
            bool gotResponse = false;
            HttpWebResponse httpWebResponse = null;
            bool requestSubmitted; 
            lock (this)
            { 
                requestSubmitted = SetRequestSubmitted(); 
                if (HaveResponse)
                { 
                    gotResponse = true;
                    httpWebResponse = _ReadAResult.Result as HttpWebResponse;
                }
                else 
                {
                    if (_ReadAResult != null) 
                    { 
                        throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                    } 

                    Async = false;

                    // Since we don't really allow switching between sync and async, if the request is already async, this needs to 
                    // capture context for use in the ongoing async operations as if it were BeginGetResponse().
                    if (Async) 
                    { 
#if !FEATURE_PAL
                        ContextAwareResult readResult = new ContextAwareResult(IdentityRequired, true, this, null, null); 
#else
                        ContextAwareResult readResult = new ContextAwareResult(false, true, this, null, null);
#endif
                        readResult.StartPostingAsyncOp(false); 
                        readResult.FinishPostingAsyncOp();
                        _ReadAResult = readResult; 
                    } 
                    else
                    { 
                        _ReadAResult = new LazyAsyncResult(this, null, null);
                    }
                }
            } 

            // See if we need to do the call-done processing here. 
            CheckDeferredCallDone(stream); 

            if (!gotResponse) 
            {
                //The previous call may have been async.  If we are now doing a sync call, we should
                //use the timeout
                if (_Timer == null){ 
                    _Timer = TimerQueue.CreateTimer(s_TimeoutCallback, this);
                } 
 

                // Save Off verb, and use it to make the request 
                if (!requestSubmitted) {
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + ": resetting CurrentMethod to " + _OriginVerb);
                    CurrentMethod = _OriginVerb;
                } 

                // If we're here it's because we don't have the response yet. We may have 
                //  already submitted the request, but if not do so now. 
                while (m_Retry) {
                    // Keep looping in case there are redirects, auth re-requests, etc 
                    BeginSubmitRequest();
                }

                while(!Async && Aborted && !_ReadAResult.InternalPeekCompleted) 
                {
                    // spin untill the _CoreResponse is set 
                    if (!(_CoreResponse is Exception)) 
                        Thread.SpinWait(1);
                    else 
                        CheckWriteSideResponseProcessing();
                }

                httpWebResponse = _ReadAResult.InternalWaitForCompletion() as HttpWebResponse; 
                _ReadAResult.EndCalled = true;
            } 
 
            if (httpWebResponse == null)
            { 
                if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetResponse", _ReadAResult.Result as Exception);
                throw (Exception) _ReadAResult.Result;
            }
 
            GlobalLog.Assert(httpWebResponse.ResponseStream != null, "HttpWebRequest#{0}::GetResponse()|httpWebResponse.ResponseStream == null", ValidationHelper.HashString(this));
            if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponse", httpWebResponse); 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse", ValidationHelper.HashString(httpWebResponse)); 
            return httpWebResponse;
#if DEBUG 
            }
#endif
        }
 
        internal void WriteCallDone(ConnectStream stream, ConnectionReturnResult returnResult)
        { 
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone()"); 

            // Make sure this is the user stream. 
            if (!object.ReferenceEquals(stream, _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream))
            {
                GlobalLog.Assert(object.ReferenceEquals(stream, _SubmitWriteStream), "HttpWebRequest#{0}::CallDone|Called from invalid stream.", ValidationHelper.HashString(this));
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called for resubmit stream"); 
                stream.ProcessWriteCallDone(returnResult);
                return; 
            } 

            // If we're still writing headers in GetRequestStream, don't delay, or GetRequestStream will hang. 
            if (!UserRetrievedWriteStream)
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called during headers");
                stream.ProcessWriteCallDone(returnResult); 
                return;
            } 
 
            object pendResult = returnResult == null ? (object) Missing.Value : returnResult;
            object oldResult = Interlocked.CompareExchange(ref m_PendingReturnResult, pendResult, null); 
            if (oldResult == DBNull.Value)
            {
                stream.ProcessWriteCallDone(returnResult);
            } 
#if TRAVE
            else if (oldResult == null) 
            { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - deferring processing");
            } 
            else
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - ignoring duplicate call.  typeof(oldResult):" + oldResult.GetType().ToString());
            } 
#endif
        } 
 
        internal void NeedEndSubmitRequest()
        { 
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::NeedEndSubmitRequest()");

            object oldResult = Interlocked.CompareExchange(ref m_PendingReturnResult, NclConstants.Sentinel, null);
            if (oldResult == DBNull.Value) 
            {
                EndSubmitRequest(); 
            } 
#if TRAVE
            else if (oldResult == null) 
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::NeedEndSubmitRequest() - deferring processing");
            }
#endif 
            else
            { 
                GlobalLog.Assert(oldResult == null, "HttpWebRequest#{0}::NeedEndSubmitRequest()|Duplicate call.  typeof(oldResult):", ValidationHelper.HashString(this), oldResult != null ? oldResult.GetType().ToString() : "null"); 
            }
        } 

        /*
            Accessor:   Address
 
            This is just a simple Uri that is returned, indicating the end result
            of the request, after any possible Redirects, etc, that may transpire 
            during the request.  This was added to handle this case since RequestUri 
            will not change from the moment this Request is created.
 
            Input:

            Returns: The Uri for this request..
 

        */ 
        ///  
        ///    
        ///       Gets the Uri that actually responded to the request. 
        ///    
        /// 
        public Uri Address {
            get { 
                return _Uri;
            } 
        } 

 
        /// 
        ///    Gets/Sets Deletegate used to signal us on Continue callback
        /// 
        public HttpContinueDelegate ContinueDelegate { 
            get {
                return _ContinueDelegate; 
            } 
            set {
                _ContinueDelegate = value; 
            }
        }

        internal void CallContinueDelegateCallback(object state) 
        {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CallContinueDelegateCallback"); 
            CoreResponseData response = (CoreResponseData) state; 
            ContinueDelegate((int) response.m_StatusCode, response.m_ResponseHeaders);
        } 


        /// 
        ///     
        ///       Gets the service point used for this request.  Looks up the ServicePoint for given Uri,
        ///         one isn't already created and assigned to this HttpWebRequest. 
        ///     
        /// 
        public ServicePoint ServicePoint { 
            get {
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif 
                return FindServicePoint(false);
#if DEBUG 
                } 
#endif
            } 
        }

        /// 
        ///  
        public int MaximumAutomaticRedirections {
            get { 
                return _MaximumAllowedRedirections; 
            }
            set { 
                if (value <= 0) {
                    throw new ArgumentException(SR.GetString(SR.net_toosmall), "value");
                }
                _MaximumAllowedRedirections = value; 
            }
        } 
 
        /// 
        ///     
        ///       Gets or sets the request method.
        ///       This method represents the initial origin Verb, this is unchanged/uneffected by redirects
        ///    
        ///  
        public override string Method {
            get { 
                return _OriginVerb.Name; 
            }
            set { 
                if (ValidationHelper.IsBlankString(value)) {
                    throw new ArgumentException(SR.GetString(SR.net_badmethod), "value");
                }
 
                if (ValidationHelper.IsInvalidHttpString(value)) {
                    throw new ArgumentException(SR.GetString(SR.net_badmethod), "value"); 
                } 
                _OriginVerb = KnownHttpVerb.Parse(value);
            } 
        }

        internal KnownHttpVerb CurrentMethod {
            get { 
                return _Verb != null ? _Verb : _OriginVerb;
            } 
            set{ 
                _Verb = value;
            } 
        }

        /// 
        ///     
        ///       Provides authentication information for the request.
        ///     
        ///  
        public override ICredentials Credentials {
            get { 
                return _AuthInfo;
            }
            set {
                _AuthInfo = value; 
            }
        } 
 
        /// 
        ///     
        ///       Allows us to use generic default credentials.
        ///    
        /// 
        public override bool UseDefaultCredentials { 
            get {
                return (Credentials is SystemNetworkCredential) ? true : false; 
            } 
            set {
                if (RequestSubmitted) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_writestarted));
                }
                _AuthInfo = value ? CredentialCache.DefaultCredentials : null;
            } 
        }
 
        ///  
        ///    
        ///       True if we're tunneling SSL through a proxy 
        ///    
        /// 
        internal bool IsTunnelRequest {
            get { 
                return (_Booleans&Booleans.IsTunnelRequest)!=0;
            } 
            set { 
                if (value) {
                    _Booleans |= Booleans.IsTunnelRequest; 
                }
                else {
                    _Booleans &= ~Booleans.IsTunnelRequest;
                } 
            }
        } 
 
        //
        // ConnectionGroupName - used to control which group 
        //  of connections we use, by default should be null
        //
        /// 
        ///    [To be supplied.] 
        /// 
        public override string ConnectionGroupName { 
            get { 
                return _ConnectionGroupName;
            } 
            set {
                _ConnectionGroupName = value;
            }
        } 

        internal bool InternalConnectionGroup 
        { 
            /* Consider removing
            get 
            {
                return m_InternalConnectionGroup;
            }
            */ 

            set 
            { 
                m_InternalConnectionGroup = value;
            } 
        }


        ///  
        ///    
        ///       A collection of HTTP headers stored as name value pairs. 
        ///     
        /// 
        public override WebHeaderCollection Headers { 
            get {
                return _HttpRequestHeaders;
            }
            set { 

                // we can't change headers after they've already been sent 
                if ( RequestSubmitted ) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 

                WebHeaderCollection webHeaders = value;
                WebHeaderCollection newWebHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebRequest);
 
                // Copy And Validate -
                // Handle the case where their object tries to change 
                //  name, value pairs after they call set, so therefore, 
                //  we need to clone their headers.
                // 

                foreach (String headerName in webHeaders.AllKeys ) {
                    newWebHeaders.Add(headerName,webHeaders[headerName]);
                } 

                _HttpRequestHeaders = newWebHeaders; 
            } 
        }
 
        /// 
        ///    
        ///       Gets or sets the proxy information for a request.
        ///     
        /// 
        public override IWebProxy Proxy { 
            get { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) { 
#endif
                ExceptionHelper.WebPermissionUnrestricted.Demand();
                return _Proxy;
#if DEBUG 
                }
#endif 
            } 
            set {
#if DEBUG 
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif
                ExceptionHelper.WebPermissionUnrestricted.Demand();
                // we can't change the proxy, while the request is already fired 
                if ( RequestSubmitted ) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                InternalProxy = value;
#if DEBUG 
                }
#endif
            }
        } 

        internal IWebProxy InternalProxy { 
            get { 
                return _Proxy;
            } 
            set {
                ProxySet = true;
                _Proxy = value;
                if (_ProxyChain != null) 
                {
                    _ProxyChain.Dispose(); 
                } 
                _ProxyChain = null;
 
                // since the service point is based on our proxy, make sure,
                // that we reresolve it
                ServicePoint servicePoint = FindServicePoint(true);
            } 
        }
 
 
        // HTTP Version
        ///  
        ///    
        ///       Gets and sets
        ///       the HTTP protocol version used in this request.
        ///     
        /// 
        public Version ProtocolVersion { 
            get { 
                return IsVersionHttp10 ? HttpVersion.Version10 : HttpVersion.Version11;
            } 
            set {
                if (value.Equals(HttpVersion.Version11)) {
                    IsVersionHttp10 = false;
                } 
                else if (value.Equals(HttpVersion.Version10)) {
                    IsVersionHttp10 = true; 
                } 
                else {
                    throw new ArgumentException(SR.GetString(SR.net_wrongversion), "value"); 
                }
            }
        }
 
        /// 
        ///     
        ///       Gets and sets the value of the Content-Type header. Null clears it out. 
        ///    
        ///  
        public override String ContentType {
            get {
                return _HttpRequestHeaders[HttpKnownHeaderNames.ContentType];
            } 
            set {
                SetSpecialHeaders(HttpKnownHeaderNames.ContentType, value); 
            } 
        }
 
        /// 
        ///    Sets the media type header
        /// 
        public string MediaType { 
            get {
                return _MediaType; 
            } 
            set {
                _MediaType = value; 
            }
        }

        ///  
        ///    
        ///       Gets or sets the value of the Transfer-Encoding header. Setting null clears it out. 
        ///     
        /// 
        public string TransferEncoding { 
            get {
                return _HttpRequestHeaders[HttpKnownHeaderNames.TransferEncoding];
            }
            set { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) { 
#endif 
                bool fChunked;
                // 
                // on blank string, remove current header
                //
                if (ValidationHelper.IsBlankString(value)) {
                    // 
                    // if the value is blank, then remove the header
                    // 
                    _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding); 
                    return;
                } 

                //
                // if not check if the user is trying to set chunked:
                // 
                string newValue = value.ToLower(CultureInfo.InvariantCulture);
                fChunked = (newValue.IndexOf(ChunkedHeader) != -1); 
 
                //
                // prevent them from adding chunked, or from adding an Encoding without 
                //  turing on chunked, the reason is due to the HTTP Spec which prevents
                //  additional encoding types from being used without chunked
                //
                if (fChunked) { 
                    throw new ArgumentException(SR.GetString(SR.net_nochunked), "value");
                } 
                else if (!SendChunked) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_needchunked));
                } 
                else {
                    _HttpRequestHeaders.CheckUpdate(HttpKnownHeaderNames.TransferEncoding, value);
                }
#if DEBUG 
                }
#endif 
            } 
        }
 
        /// 
        ///    
        ///       Gets and sets the value of the Connection header. Setting null clears the header out.
        ///     
        /// 
        public string Connection { 
            get { 
                return _HttpRequestHeaders[HttpKnownHeaderNames.Connection];
            } 
            set {
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif 
                bool fKeepAlive;
                bool fClose; 
 
                //
                // on blank string, remove current header 
                //
                if (ValidationHelper.IsBlankString(value)) {
                    _HttpRequestHeaders.Remove(HttpKnownHeaderNames.Connection);
                    return; 
                }
 
                string newValue = value.ToLower(CultureInfo.InvariantCulture); 

                fKeepAlive = (newValue.IndexOf("keep-alive") != -1) ; 
                fClose =  (newValue.IndexOf("close") != -1) ;

                //
                // Prevent keep-alive and close from being added 
                //
 
                if (fKeepAlive || 
                    fClose) {
                    throw new ArgumentException(SR.GetString(SR.net_connarg), "value"); 
                }
                else {
                    _HttpRequestHeaders.CheckUpdate(HttpKnownHeaderNames.Connection, value);
                } 
#if DEBUG
                } 
#endif 
            }
        } 

        /// 
        ///    
        ///       Gets or sets the value of the Accept header. 
        ///    
        ///  
        public string Accept { 
            get {
                return _HttpRequestHeaders[HttpKnownHeaderNames.Accept]; 
            }
            set {
                SetSpecialHeaders(HttpKnownHeaderNames.Accept, value);
            } 
        }
 
        ///  
        ///    
        ///       Gets or sets the value of the Referer header. 
        ///    
        /// 
        public string Referer {
            get { 
                return _HttpRequestHeaders[HttpKnownHeaderNames.Referer];
            } 
            set { 
                SetSpecialHeaders(HttpKnownHeaderNames.Referer, value);
            } 
        }

        /// 
        ///     
        ///       Gets or sets the value of the User-Agent header.
        ///     
        ///  
        public string UserAgent {
            get { 
                return _HttpRequestHeaders[HttpKnownHeaderNames.UserAgent];
            }
            set {
                SetSpecialHeaders(HttpKnownHeaderNames.UserAgent, value); 
            }
        } 
 

        /* 
            Accessor:   Expect

            The property that controls the Expect header
 
            Input:
                string Expect, null clears the Expect except for 100-continue value 
 
            Returns: The value of the Expect on get.
 
        */

        /// 
        ///     
        ///       Gets or sets the value of the Expect header.
        ///     
        ///  
        public string Expect {
            get { 
                return _HttpRequestHeaders[HttpKnownHeaderNames.Expect];
            }
            set {
#if DEBUG 
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif 
                // only remove everything other than 100-cont 
                bool fContinue100;
 
                //
                // on blank string, remove current header
                //
 
                if (ValidationHelper.IsBlankString(value)) {
                    _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Expect); 
                    return; 
                }
 
                //
                // Prevent 100-continues from being added
                //
 
                string newValue = value.ToLower(CultureInfo.InvariantCulture);
 
                fContinue100 = (newValue.IndexOf(ContinueHeader) != -1) ; 

                if (fContinue100) { 
                    throw new ArgumentException(SR.GetString(SR.net_no100), "value");
                }
                else {
                    _HttpRequestHeaders.CheckUpdate(HttpKnownHeaderNames.Expect, value); 
                }
#if DEBUG 
                } 
#endif
            } 
        }

        /// 
        ///     
        ///       Gets or sets the value of the If-Modified-Since header.
        ///     
        ///  
        public DateTime IfModifiedSince {
            get { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif
                string ifmodHeaderValue = _HttpRequestHeaders[HttpKnownHeaderNames.IfModifiedSince]; 

                if (ifmodHeaderValue == null) { 
                    return DateTime.Now; 
                }
                else if (_CachedIfModifedSince != DateTime.MinValue) { 
                    return _CachedIfModifedSince;
                }

                return HttpProtocolUtils.string2date(ifmodHeaderValue); 
#if DEBUG
                } 
#endif 
            }
            set { 
#if DEBUG
                using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) {
#endif
                SetSpecialHeaders(HttpKnownHeaderNames.IfModifiedSince, HttpProtocolUtils.date2string(value)); 
                _CachedIfModifedSince = value;
#if DEBUG 
                } 
#endif
            } 
        }

        internal byte[] WriteBuffer {
            get { 
                return _WriteBuffer;
            } 
        } 

        // 
        // Frequently usedheaders made available as properties,
        //   the following headers add or remove headers taking care
        //   of special cases due to their unquie qualities within
        //   the net handlers, 
        //
        //  Note that all headers supported here will be disallowed, 
        //    and not accessable through the normal Header objects. 
        //
 
        /*
            Accessor:   SetSpecialHeaders

            Private method for removing duplicate code which removes and 
              adds headers that are marked private
 
            Input:  HeaderName, value to set headers 

            Returns: none 


        */
 
        private void SetSpecialHeaders(string HeaderName, string value) {
            value = WebHeaderCollection.CheckBadChars(value, true); 
            _HttpRequestHeaders.RemoveInternal(HeaderName); 
            if (value.Length != 0) {
                _HttpRequestHeaders.AddInternal(HeaderName, value); 
            }
        }

        /* 
            Abort - Attempts to abort pending request,
 
            This calls into the delegate, and then closes any pending streams. 

            Input: none 

            Returns: none

        */ 
        public override void Abort()
        { 
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User /* | ThreadKinds.Async would be nice */)) {
#endif 
            Abort(null, AbortState.Public);
#if DEBUG
            }
#endif 
        }
 
        private void Abort(Exception exception, int abortState) 
        {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort()"); 
            if (Logging.On) Logging.Enter(Logging.Web, this, "Abort", (exception == null? "" :  exception.Message));

            if(Interlocked.CompareExchange(ref m_Aborted, abortState, 0) == 0) // public abort will never drain streams
            { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::Abort() - " + exception);
 
                m_OnceFailed = true; 
                CancelTimer();
 
                WebException webException = exception as WebException;
                if (exception == null)
                {
                    webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled); 
                }
                else if (webException == null) 
                { 
                    webException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), exception, WebExceptionStatus.RequestCanceled, _HttpResponse);
                } 

                try
                {
#if DEBUG 
                bool setResponseCalled = false;
                try 
                { 
#endif
                    // Want to make sure that other threads see that we're aborted before they set an abort delegate, or that we see 
                    // the delegate if they might have missed that we're aborted.
                    Thread.MemoryBarrier();
                    HttpAbortDelegate abortDelegate = _AbortDelegate;
#if DEBUG 
                    m_AbortDelegateUsed = abortDelegate == null ? (object) DBNull.Value : abortDelegate;
#endif 
                    if (abortDelegate == null || abortDelegate(this, webException)) 
                    {
                        // We don't have a connection associated with this request 

                        LazyAsyncResult chkConnectionAsyncResult = Async? null: ConnectionAsyncResult;
                        LazyAsyncResult chkReaderAsyncResult = Async? null: ConnectionReaderAsyncResult;
 
#if DEBUG
                        setResponseCalled = true; 
#endif 
                        SetResponse(webException);
 
                        if (chkConnectionAsyncResult != null)
                            chkConnectionAsyncResult.InvokeCallback(webException);
                        if (chkReaderAsyncResult != null)
                            chkReaderAsyncResult.InvokeCallback(webException); 
                    }
#if DEBUG 
                } 
                catch (Exception stressException)
                { 
                    t_LastStressException = stressException;
                    if (!NclUtilities.IsFatal(stressException)){
                        GlobalLog.Assert(setResponseCalled, "HttpWebRequest#{0}::Abort|{1}", ValidationHelper.HashString(this), stressException.Message);
                    } 
                    throw;
                } 
#endif 
                }
                catch (Exception ex) 
                {
                    if (NclUtilities.IsFatal(ex)) throw;
                }
                catch { } 
            }
 
            if(Logging.On)Logging.Exit(Logging.Web, this, "Abort", ""); 
        }
 
        // Cancel any pending timer.
        private void CancelTimer()
        {
            TimerThread.Timer timer = _Timer; 
            if (timer != null)
            { 
                timer.Cancel(); 
            }
        } 

        // TimeoutCallback - Called by the TimerThread to abort a request.  This just posts ThreadPool work item - Abort() does too
        // much to be done on the timer thread (timer thread should never block or call user code).
        private static void TimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context) 
        {
            ThreadPool.UnsafeQueueUserWorkItem(s_AbortWrapper, context); 
        } 

        private static void AbortWrapper(object context) 
        {
#if DEBUG
            GlobalLog.SetThreadSource(ThreadKinds.Worker);
            using (GlobalLog.SetThreadKind(ThreadKinds.System)) { 
#endif
            ((HttpWebRequest) context).Abort(new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout), AbortState.Public); 
#if DEBUG 
            }
#endif 
        }

        /*
            FindServicePoint - Finds the ServicePoint for this request 

            This calls the FindServicePoint off of the ServicePointManager 
            to determine what ServicePoint to use.  When our proxy changes, 
            or there is a redirect, this should be recalled to determine it.
 
            Input:  forceFind        - regardless of the status, always call FindServicePoint

            Returns: ServicePoint
 
        */
        private ServicePoint FindServicePoint(bool forceFind) { 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::FindServicePoint"); 

            ServicePoint servicePoint = _ServicePoint; 
            if ( servicePoint == null || forceFind ) {
                lock(this) {
                    //
                    // we will call FindServicePoint - iff 
                    //  - there is no service point ||
                    //  - we are forced to find one, usually due to changes of the proxy or redirection 
                    // 

                    if ( _ServicePoint == null || forceFind ) { 

                        if (!ProxySet) {
                            _Proxy = WebRequest.InternalDefaultWebProxy;
                        } 
                        if (_ProxyChain != null)
                        { 
                            _ProxyChain.Dispose(); 
                        }
                        _ServicePoint = ServicePointManager.FindServicePoint(_Uri, _Proxy, out _ProxyChain, ref _AbortDelegate, ref m_Aborted); 
                        if(Logging.On)Logging.Associate(Logging.Web, this, _ServicePoint);
                    }
                }
                servicePoint = _ServicePoint; 
            }
 
            return servicePoint; 
        }
 
        /*
            InvokeGetRequestStreamCallback - Notify our GetRequestStream caller

            This is needed to tell our caller that we're finished, 
            and he can go ahead and write to the stream.
        */ 
        private void InvokeGetRequestStreamCallback() 
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback"); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback");

            LazyAsyncResult asyncResult = _WriteAResult;
            GlobalLog.Assert(asyncResult == null || this == (HttpWebRequest)asyncResult.AsyncObject, "HttpWebRequest#{0}::InvokeGetRequestStreamCallback()|this != asyncResult.AsyncObject", ValidationHelper.HashString(this)); 

            if (asyncResult != null) { 
                try { 
                    asyncResult.InvokeCallback(_SubmitWriteStream);
                } 
                catch (Exception exception) {
                    if (NclUtilities.IsFatal(exception)) throw;

                    Abort(exception, AbortState.Public); 
                    GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback", exception);
                    throw; 
                } 
            }
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::InvokeGetRequestStreamCallback", "success"); 
        }

        /*
            RequestSubmitDone - Handle submit done callback. 

            This is our submit done handler, called by the underlying connection 
            code when a stream is available for our use. We save the stream for 
            later use and signal the wait event.
 
            We also handle the continuation/termination of a BeginGetRequestStream,
            by saving out the result and calling its callback if needed.

            Input:  SubmitStream        - The stream we may write on. 
                    Status              - The status of the submission.
 
            Returns: Nothing. 

        */ 
        internal void SetRequestSubmitDone(ConnectStream submitStream) {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone", ValidationHelper.HashString(submitStream));
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone");
 
            if (!Async) {
                ConnectionAsyncResult.InvokeCallback(); 
            } 

            if (AllowWriteStreamBuffering) { 
                submitStream.EnableWriteBuffering();
            }

            if (submitStream.CanTimeout) { 
                submitStream.ReadTimeout = ReadWriteTimeout;
                submitStream.WriteTimeout = ReadWriteTimeout; 
            } 
            if(Logging.On)Logging.Associate(Logging.Web, this, submitStream);
            _SubmitWriteStream = submitStream; 

            //
            // This line is needed ONLY if we got a connect failure (Abort can still happen at random time)
            // CallDone will check for the write side response processing and this is what we want. 
            // Note that Sync case already has a separate path to check for the response
            // 
            if (Async && _CoreResponse != null && (object)_CoreResponse != (object)DBNull.Value) 
            {
                GlobalLog.Assert(_CoreResponse is Exception, "SetRequestSubmitDone()|Found offensive response right after getting connection ({0}).", _CoreResponse); 
                submitStream.CallDone();
                GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone() - already have a core response", _CoreResponse.GetType().FullName);
                return;
            } 

            EndSubmitRequest(); 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone"); 
        }
 

        internal void WriteHeadersCallback(WebExceptionStatus errorStatus, ConnectStream stream, bool async)
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteHeadersCallback", ValidationHelper.HashString(stream)); 
            if(errorStatus == WebExceptionStatus.Success)
            { 
                bool completed = EndWriteHeaders(async); 
                if (!completed) {
                    errorStatus = WebExceptionStatus.Pending; 
                }
                else {
                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(stream) + "::WriteHeaders completed:true BytesLeftToWrite:" + stream.BytesLeftToWrite.ToString());
                    if (stream.BytesLeftToWrite == 0) { 
                        //
                        // didn't go pending, no data to write. we're done. 
                        // 
                        stream.CallDone();
                    } 
                }
            }

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteHeadersCallback", errorStatus.ToString()); 
        }
 
        /* 
            SetRequestContinue - Handle 100-continues on Posting
 
            This indicates to us that we need to continue posting,
            and there is no need to buffer because we are now
        */
        internal void SetRequestContinue() 
        {
            SetRequestContinue(null); 
        } 

        internal void SetRequestContinue(CoreResponseData continueResponse) 
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue");
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue");
 
            _RequestContinueCount++;
 
            if (HttpWriteMode == HttpWriteMode.None) 
            {
                GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue - not a POST type request, return"); 
                return;
            }

            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() _RequestContinueCount:" + _RequestContinueCount); 

            if (m_ContinueGate.Complete()) 
            { 
                // Generally, in Sync mode there will not be a timer (instead PollAndRead times out).  However, in mixed mode
                // there can be.  If there is a timer, whether or not to call EndWriteHeaders_Part2 depends on whether 
                // we can successfully cancel it here.  Otherwise, the timeout callback should call it.
                //
                // m_ContinueGate guards the synchronization of m_ContinueTimer.
                TimerThread.Timer timer = m_ContinueTimer; 
                m_ContinueTimer = null;
 
                // In the case there was no timer, just call EndWriteHeaders_Part2. 
                if (timer == null || timer.Cancel())
                { 
                    // Invoke the 100 continue delegate if the user supplied one and we received a 100 Continue.
                    if (continueResponse != null && ContinueDelegate != null)
                    {
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() calling ContinueDelegate()"); 
                        ExecutionContext x = Async ? GetWritingContext().ContextCopy : null;
                        if (x == null) 
                        { 
                            ContinueDelegate((int) continueResponse.m_StatusCode, continueResponse.m_ResponseHeaders);
                        } 
                        else
                        {
                            ExecutionContext.Run(x, new ContextCallback(CallContinueDelegateCallback), continueResponse);
                        } 
                    }
 
                    EndWriteHeaders_Part2(); 
                }
           } 

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue");
        }
 
        //
        // Used to keep us looping and parsing until we get a 100 continue. 
        // Since we can get more than one 100 continue during redirects or auth, we need to keep it on a counter. 
        //
        internal int RequestContinueCount { 
            get {
                return _RequestContinueCount;
            }
        } 
        //
        // This will open the write side response window, so any response processing 
        // coming before the window is closed will be delayed. 
        // CheckWriteSideResponseProcessing() becomes a must do call sometime after this method was invoked.
        // 
        internal void OpenWriteSideResponseWindow()
        {
            //
            // Multithreading: This method is called from the connection and under the connection lock 
            // It should not be subject to a race condition. Note that request.Abort() also ends up with the connection lock.
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::OpenWriteSideResponseWindow()"); 
 
            _CoreResponse = DBNull.Value;
            _NestedWriteSideCheck = 0; 
        }
        //
        // If the response is already received this method starts its processing.
        // Otheriwse the window for write side response processing is closed 
        //
        // We do not clear current response if any hence SetAndOrProcessResponse() will not go into concurent 
        // reponse processing 
        //
        internal void CheckWriteSideResponseProcessing() 
        {
            // In Sync case never close the write side window
            object responseData = Async? Interlocked.CompareExchange(ref _CoreResponse, null, DBNull.Value): _CoreResponse;
 
            if (responseData == DBNull.Value)
            { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckWriteSideResponseProcessing() - responseData = DBNull means no response yet, " +  (Async?"async: closing write side window": "sync: leaving write side window opened")); 
                return;
            } 

            if (responseData == null)
            {
                // change later on responseData = new a generic Abort WebException 
                throw new InternalException(); // we set it to DBNull.Value and want to find it now as either that value or as the real response
            } 
 
            if (!Async && ++_NestedWriteSideCheck != 1)
            { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckWriteSideResponseProcessing() - Repeated SYNC check _NestedWriteSideCheck = " + _NestedWriteSideCheck + ", response =" + responseData.GetType().FullName);
                return;
            }
 
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckWriteSideResponseProcessing() - Response is ready, process here: " + responseData.GetType().FullName);
 
            // The response has been already set and the processing was deferred until now 
            Exception exception  = responseData as Exception;
            if (exception != null) 
                SetResponse(exception);
            else
                SetResponse(responseData as CoreResponseData);
        } 
        //
        // 
        // Some kind of response is ready and this method will ether process it or defer until the write side response check. 
        //
        // Note, when an exception comes here then the request is already taken off the list and the connection is BEING closed. 
        internal void SetAndOrProcessResponse(object responseOrException)
        {
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Entered with responseOrException: " + responseOrException);
 
            if (responseOrException == null)
                throw new InternalException(); //Consider making an Assert later. If the condtion is met then this request may hang. 
 
            CoreResponseData newResponse  = responseOrException as CoreResponseData;
            WebException    newException = responseOrException as WebException; 

            object responseData = Interlocked.CompareExchange(ref _CoreResponse,  responseOrException, DBNull.Value);

            // 
            // (1) This method cannot be called with two exceptions in a row or with two responses in a row.
            // (2) If a response comes then an exception means a fatal exception overrides the response or otherwise ignored 
            // (3) If an exception comes then a response means the exception takes precedence so the response can be ignored 
            //
 
            if (responseData != null)
            {
                if (responseData.GetType() == typeof(CoreResponseData))
                { 
                     if (newResponse != null)
                         throw new InternalException();// make an assert later 
 
                     if (newException != null && newException.InternalStatus != WebExceptionInternalStatus.ServicePointFatal &&
                        newException.InternalStatus != WebExceptionInternalStatus.RequestFatal) 
                         return;
                     // Else the exception will override the response
                }
                else if (responseData.GetType() != typeof(DBNull)) 
                {
                    // Here responseData == Exception so newResponse must not be an exception 
                    if (newResponse  == null) 
                        throw new InternalException();// make an assert later that will be ignored in retail
 
                    //We have an exception and now getting a response
                    // Release that response stream to unblock the connection
                    ICloseEx closeEx = newResponse.m_ConnectStream as ICloseEx;
                    if (closeEx != null) 
                    {
                        closeEx.CloseEx(CloseExState.Silent); 
                    } 
                    else
                    { 
                        newResponse.m_ConnectStream.Close();
                    }

                    return; 
                }
            } 
 
            //
            // Can the write side process that response? 
            //
            if (responseData == DBNull.Value)
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Write Thread will procees the response."); 
                //
                // Note for a sync request a write side window is always open 
                // 
                if (!Async)
                { 
                    LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult;
                    LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult;

                    chkConnectionAsyncResult.InvokeCallback(responseOrException); // ref "responseOrException": could be anything except for AsyncTriState or stream 
                    chkReaderAsyncResult.InvokeCallback(responseOrException);     // ref "responseOrException": could be anything except for null
                } 
                return; 
            }
            else if (responseData != null) 
            {
                Exception e = responseOrException as Exception;
                if (e != null)
                { 
                    // This may happen if we failed while trying to process a response.
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Fatal Exception -> Override old response = " + responseData); 
                    SetResponse(e); 
                }
                else 
                {
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Error!!! Unexpected (1) Response already set response = " + responseData);
                    throw new InternalException();// make an assert later
                } 
                return;
            } 
 
            //
            // Can that thread process the response? 
            //
            responseData = Interlocked.CompareExchange(ref _CoreResponse,  responseOrException, null);
            if (responseData != null)
            { 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Warning!!! Unexpected (2) SetResponse, already set response = " + responseData);
 
                // This is a race with Abort, if we got an exception then re-enter SetResponse, otherwise return 
                if (newResponse != null)
                { 
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Ignoring current response while SetResponse() is processing an exception");

                    // We have an exception and now getting a response
                    // Release that response stream to unblock the connection 
                    ICloseEx closeEx = newResponse.m_ConnectStream as ICloseEx;
                    if (closeEx != null) 
                    { 
                        closeEx.CloseEx(CloseExState.Silent);
                    } 
                    else
                    {
                        newResponse.m_ConnectStream.Close();
                    } 

                    return; 
                } 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetAndOrProcessResponse() - Forcing new exception to re-enter SetResponse() that is being processed with CoreResponseData");
            } 

            if (!Async)
                throw new InternalException(); //Consider making an Assert later. If the condition is met it _might_ process a sync request on non submitting thread.
 
            // For this request the write side response window was already closed so we have to procees the response
            if (newResponse != null) 
                SetResponse(newResponse); 
            else
                SetResponse(responseOrException as Exception); 
        }
        //
        // When we got a live response, this method will construct the response object
        // and then consult with caching protocol on the appropriate action. 
        // On return the response can be re-created.
        // Under some cases this method may initate retrying of the current request. 
        // 
        private void SetResponse(CoreResponseData coreResponseData) {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse"); 
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse - coreResponseData=" + ValidationHelper.HashString(coreResponseData));

            try {
                // Consider removing this block as all these should be already signalled 
                if (!Async)
                { 
                    LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult; 
                    LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult;
 
                    chkConnectionAsyncResult.InvokeCallback(coreResponseData); // ref "coreResponseData": could be anything except for AsyncTriState or stream
                    chkReaderAsyncResult.InvokeCallback(coreResponseData);     // ref "coreResponseData": could be anything except for null
                }
 
                if (coreResponseData != null)
                { 
                    if (coreResponseData.m_ConnectStream.CanTimeout) 
                    {
                        coreResponseData.m_ConnectStream.WriteTimeout = ReadWriteTimeout; 
                        coreResponseData.m_ConnectStream.ReadTimeout = ReadWriteTimeout;
                    }
                    _HttpResponse = new HttpWebResponse(_Uri, CurrentMethod, coreResponseData, _MediaType, UsesProxySemantics, AutomaticDecompression);
 
                    if(Logging.On)Logging.Associate(Logging.Web, this, coreResponseData.m_ConnectStream);
                    if(Logging.On)Logging.Associate(Logging.Web, this, _HttpResponse); 
                    ProcessResponse(); 
                }
                else 
                {
                    GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse()", "coreResponseData == null");
                    Abort(null, AbortState.Public);
                    GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", new InternalException()); 
                }
            } 
            catch (Exception exception) { 
                Abort(exception, AbortState.Internal);
                GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", exception); 
            }
            return;
        }
 
        /*++
 
        Routine Description: 

            Wakes up blocked threads, so they can read response object, 
              from the result

            We also handle the continuation/termination of a BeginGetResponse,
            by saving out the result and calling its callback if needed. 

 
        --*/ 
        private void ProcessResponse() {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ProcessResponse", "From Cache = " + _HttpResponse.IsFromCache); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ProcessResponse");

            HttpProcessingResult httpResult = HttpProcessingResult.Continue;
            Exception exception = null; 

            // handle redirects, authentication, and such 
            httpResult = DoSubmitRequestProcessing(ref exception); 

            if (httpResult == HttpProcessingResult.Continue) 
            {
                CancelTimer();

                object result = exception != null ? (object) exception : (object) _HttpResponse; 

                if (_ReadAResult == null) 
                { 
                    lock (this)
                    { 
                        if (_ReadAResult == null)
                        {
                            _ReadAResult = new LazyAsyncResult(null, null, null, result);  //never throws
                        } 
                    }
                } 
 
                try
                { 
                    FinishRequest(_HttpResponse, exception); // never throws

                    _ReadAResult.InvokeCallback(result);
 
                    try
                    { 
                        SetRequestContinue(); 
                    }
                    catch { } 
                }
                catch (Exception e)
                {
                    Abort(e, AbortState.Public); 
                    throw;
                } 
                finally 
                {
                    // If request was already aborted the response will not be set on asyncResult, hence abort it now 
                    if (exception == null && _ReadAResult.Result != (object) _HttpResponse)
                    {
                        WebException webException = _ReadAResult.Result as WebException;
                        if (webException != null && webException.Response != null) 
                        {
                            GlobalLog.Assert(object.ReferenceEquals(webException.Response, _HttpResponse), "HttpWebRequset#{0}::ProcessResponse|Different HttpWebResponse in exception versus _HttpResponse.", ValidationHelper.HashString(this)); 
                            _HttpResponse.Abort();  // never throws 
                        }
                    } 
                }
            }
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ProcessResponse");
        } 

        // 
        // Process an exception and optionally set request for retrying 
        //
        private void SetResponse(Exception E) { 
#if DEBUG
            bool callbackInvoked = false;
            try
            { 
#endif
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", E.ToString() + "/*** SETRESPONSE IN ERROR ***"); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse"); 

            HttpProcessingResult httpResult = HttpProcessingResult.Continue; 

            //
            // Preserve the very first web exception occured if it was fatal
            // 
            WebException webException = HaveResponse ? _ReadAResult.Result as WebException : null;
            WebException newWebException = E as WebException; 
            if (webException != null && (webException.InternalStatus == WebExceptionInternalStatus.RequestFatal || 
                webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal) &&
                (newWebException == null || newWebException.InternalStatus != WebExceptionInternalStatus.RequestFatal)) 
            {
                E = webException;
            }
            else 
            {
                webException = newWebException; 
            } 

            if (E != null) 
            {
                if (Logging.On) Logging.Exception(Logging.Web, this, "", webException);
            }
 
            try {
                if ( webException != null && 
                     (webException.InternalStatus == WebExceptionInternalStatus.Isolated || 
                     webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal ||
                     (webException.InternalStatus == WebExceptionInternalStatus.Recoverable && !m_OnceFailed))) 
                {

                    if (webException.InternalStatus == WebExceptionInternalStatus.Recoverable)
                        m_OnceFailed = true; 

                    Pipelined = false; 
 
                    if (_SubmitWriteStream != null && _OldSubmitWriteStream == null && _SubmitWriteStream.BufferOnly) {
                        _OldSubmitWriteStream = _SubmitWriteStream; 
                    }

                    httpResult = DoSubmitRequestProcessing(ref E);
                } 
            }
            catch (Exception unexpectedException) 
            { 
                if (NclUtilities.IsFatal(unexpectedException)) throw;
 
                // This is highly unexpected but if happens would result into Aborted exception with caught one as an inner exception
                httpResult = HttpProcessingResult.Continue;
                E = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), unexpectedException, WebExceptionStatus.RequestCanceled, _HttpResponse);
            } 
            finally
            { 
                if (httpResult == HttpProcessingResult.Continue) 
                {
                    CancelTimer(); 

                    if (!(E is WebException) && !(E is SecurityException))
                    {
                        if (_HttpResponse==null) { 
                            E = new WebException(E.Message, E);
                        } 
                        else { 
                            E = new WebException(
                                SR.GetString( 
                                    SR.net_servererror,
                                    NetRes.GetWebStatusCodeString(
                                        ResponseStatusCode,
                                        _HttpResponse.StatusDescription)), 
                                E,
                                WebExceptionStatus.ProtocolError, 
                                _HttpResponse ); 
                        }
                    } 

                    LazyAsyncResult writeAResult;
                    LazyAsyncResult readAResult = null;
 
                    // Async Abort may happen at any time including when the request is being cleared
                    // and resubmitted hence using checked response. 
                    HttpWebResponse chkResponse = _HttpResponse; 

                    lock (this) 
                    {
                        writeAResult = _WriteAResult;

                        if (_ReadAResult == null) 
                        {
                            _ReadAResult = new LazyAsyncResult(null, null, null, E); //never throws 
                        } 
                        else
                        { 
                            readAResult = _ReadAResult;
                        }
                    }
 
                    try
                    { 
                        FinishRequest(chkResponse, E); //never throws 

                        try 
                        {
                            if (writeAResult != null) {
                                writeAResult.InvokeCallback(E);
                            } 
                        }
                        finally 
                        { 
                            if (readAResult != null) {
#if DEBUG 
                                callbackInvoked = true;
#endif
                                readAResult.InvokeCallback(E);
                            } 
                        }
                    } 
                    finally 
                    {
                        chkResponse = _ReadAResult.Result as HttpWebResponse; 

                        // If the response was already set that exception closes it.
                        if (chkResponse != null)
                        { 
                            chkResponse.Abort();    //never throws
                        } 
 
                        if (CacheProtocol != null)
                        { 
                            CacheProtocol.Abort();  //never throws
                        }
                    }
                } 
#if DEBUG
                else 
                { 
                    callbackInvoked = true;
                } 
#endif
            }
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", httpResult.ToString());
#if DEBUG 
            }
            catch (Exception exception) 
            { 
                t_LastStressException = exception;
 
                if (!NclUtilities.IsFatal(exception)){
                    GlobalLog.Assert(callbackInvoked, "HttpWebRequest#{0}::SetResponse|{1}", ValidationHelper.HashString(this), exception.Message);
                }
                throw; 
            }
#endif 
        } 

#if DEBUG 
        [ThreadStatic]
        private static Exception t_LastStressException;
        private object m_AbortDelegateUsed;
#endif 

        private bool IdentityRequired 
        { 
            get
            { 
                // Skip token capturing if no credentials are used or they don't include a default one.
                // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be.
                CredentialCache cache;
                return Credentials != null && 
                       ComNetOS.IsWinNt &&
                       (Credentials is SystemNetworkCredential || 
                        (!(Credentials is NetworkCredential) && 
                         ((cache = Credentials as CredentialCache) == null ||
                          cache.IsDefaultInCache 
                         )
                        )
                       );
            } 
        }
 
        // Return null only on Sync (if we're on the Sync thread).  Otherwise throw if no context is available. 
        internal override ContextAwareResult GetConnectingContext()
        { 
            if (!Async)
            {
                GlobalLog.ThreadContract(ThreadKinds.User | ThreadKinds.Sync, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetConnectingContext");
                return null; 
            }
 
 			// _WriteARequest == null is the case where the user specifies POST but doesn't call GetRequestStream(). 
            ContextAwareResult context =
                (HttpWriteMode == HttpWriteMode.None || _OldSubmitWriteStream != null || _WriteAResult == null ? 
                _ReadAResult : _WriteAResult) as ContextAwareResult;
            if (context == null)
            {
                GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetConnectingContext", "Called while asynchronous connecting phase not in progress."); 
                throw new InternalException();
            } 
 
            return context;
        } 

        // Return null only on Sync (if we're on the Sync thread).  Otherwise throw if no context is available.
        internal override ContextAwareResult GetWritingContext()
        { 
            if (!Async)
            { 
                GlobalLog.ThreadContract(ThreadKinds.User | ThreadKinds.Sync, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetWritingContext"); 
                return null;
            } 

			// _WriteARequest == null is the case where the user specifies POST but doesn't call GetRequestStream().
            ContextAwareResult context =  (HttpWriteMode == HttpWriteMode.None || HttpWriteMode == HttpWriteMode.Buffer ||
                m_PendingReturnResult == DBNull.Value || m_OriginallyBuffered || _WriteAResult == null ? 
                _ReadAResult : _WriteAResult) as ContextAwareResult;
            if (context == null) 
            { 
                GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetWritingContext", "Called while asynchronous writing phase not in progress.");
                throw new InternalException(); 
            }

            return context;
        } 

        // Return null only on Sync (if we're on the Sync thread).  Otherwise throw if no context is available. 
        internal override ContextAwareResult GetReadingContext() 
        {
            if (!Async) 
            {
                GlobalLog.ThreadContract(ThreadKinds.User | ThreadKinds.Sync, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetReadingContext");
                return null;
            } 

            ContextAwareResult context = _ReadAResult as ContextAwareResult; 
            if (context == null) 
            {
                GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetReadingContext|Called while asynchronous reading phase not in progress."); 
                throw new InternalException();
            }

            return context; 
        }
 
 
        /*++
 
            BeginSubmitRequest: Begins Submit off a request to the network.

            This is called when we need to transmit an Async Request, but
            this function only servers to activate the submit, and does not 
            actually block
 
            Called when we want to submit a request to the network. We do several 
            things here - look for a proxy, find the service point, etc. In the
            end we call the service point to get access (via a stream) to the 
            underlying connection, then serialize our headers onto that connection.
            The actual submission request to the service point is async, so we
            submit the request and then return, to allow the async to run its course.
 
            Input:
                forceFind - insures that always get a new ServicePoint, 
                    needed on redirects, or where the ServicePoint may have changed 

            Returns: Nothing 

        --*/

        private void BeginSubmitRequest() 
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest"); 
            GlobalLog.ThreadContract(ThreadKinds.User, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest"); 
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest() Method:" + Method + " Address:" + Address);
 
            SubmitRequest(FindServicePoint(false));

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::BeginSubmitRequest");
        } 

        private void SubmitRequest(ServicePoint servicePoint) 
        { 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest");
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest"); 
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest() HaveResponse:" + HaveResponse + " Saw100Continue:" + Saw100Continue);

            if (!Async)
            { 
                _ConnectionAResult = new LazyAsyncResult(this, null, null);
                _ConnectionReaderAResult = new LazyAsyncResult(this, null, null); 
                OpenWriteSideResponseWindow(); 
            }
 
            if (_Timer == null && !Async){
                _Timer = TimerQueue.CreateTimer(s_TimeoutCallback, this);
            }
 
            try {
 
                if (_SubmitWriteStream != null && _SubmitWriteStream.IsPostStream) 
                {
                    // _OldSubmitWriteStream is the stream that holds real user data 
                    // In no case it can be overwritten.
                    // For multiple resubmits the ContentLength was set already, so no need call it again.
                    // on first resubmission the real user data hasn't been saved, so _OldSubmitWriteStream is null
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest() (resubmit) firstResubmission:" + (_OldSubmitWriteStream == null) + " NtlmKeepAlive:" + NtlmKeepAlive); 
                    if (_OldSubmitWriteStream == null && !_SubmitWriteStream.ErrorInStream)
                    { 
                        // save the real user data. 
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest() (resubmit) save the real user data _OldSubmitWriteStream#" + ValidationHelper.HashString(_OldSubmitWriteStream));
                        _OldSubmitWriteStream = _SubmitWriteStream; 
                    }
                    // make sure we reformat the headers before resubmitting
                    _WriteBuffer = null;
                } 

                m_Retry = false; 
 
                // If pre-authentication is requested call the AuthenticationManager
                // and add authorization header if there is response 
                if (PreAuthenticate) {
                    if (UsesProxySemantics && _Proxy != null && _Proxy.Credentials != null)
                        ProxyAuthenticationState.PreAuthIfNeeded(this, _Proxy.Credentials);
                    if (Credentials != null) 
                        ServerAuthenticationState.PreAuthIfNeeded(this, Credentials);
                } 
 
                if (WriteBuffer == null) {
                    UpdateHeaders(); 
                }

                if (CheckCacheRetrieveBeforeSubmit()) {
                    // We are done and internal Response processing is kicked in 
                    GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest CACHED RESPONSE");
                    return; 
                } 

                // At this point we are going to send a live request 
                // _AbortDelegate is set on submission process.
                servicePoint.SubmitRequest(this, GetConnectionGroupLine());
            }
            finally { 
                if (!Async)
                    CheckWriteSideResponseProcessing(); 
            } 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SubmitRequest");
        } 


        //
        // This method may be invoked as part of the request submission but 
        // before the response is received
        // Return: 
        // - True       = response is ready 
        // - False      = Proceed with the request submission
        private bool CheckCacheRetrieveBeforeSubmit() { 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheRetrieveBeforeSubmit");

            if (CacheProtocol == null) {
                return false; 
            }
 
            try 
            {
                Uri cacheUri = _Uri; 
                if (cacheUri.Fragment.Length != 0)
                    cacheUri = new Uri(cacheUri.GetParts(UriComponents.AbsoluteUri & ~UriComponents.Fragment, UriFormat.SafeUnescaped));

                CacheProtocol.GetRetrieveStatus(cacheUri, this); 

                if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) { 
                    throw CacheProtocol.ProtocolException; 
                }
 
                if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) {
                    return false;
                }
 
                if (HttpWriteMode!=HttpWriteMode.None) {
                    throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_body)); 
                } 

                // If we take it from cache, we have to kick in response processing 
                // The _CacheStream is good to return as the response stream.
                HttpRequestCacheValidator ctx = (HttpRequestCacheValidator) CacheProtocol.Validator;
                CoreResponseData responseData = new CoreResponseData();
                responseData.m_IsVersionHttp11  = ctx.CacheHttpVersion.Equals(HttpVersion.Version11); 
                responseData.m_StatusCode       = ctx.CacheStatusCode;
                responseData.m_StatusDescription= ctx.CacheStatusDescription; 
                responseData.m_ResponseHeaders  = ctx.CacheHeaders; 
                responseData.m_ContentLength    = CacheProtocol.ResponseStreamLength;
                responseData.m_ConnectStream    = CacheProtocol.ResponseStream; 
                _HttpResponse = new HttpWebResponse(_Uri, CurrentMethod, responseData, _MediaType, UsesProxySemantics, AutomaticDecompression);
                _HttpResponse.InternalSetFromCache = true;
                _HttpResponse.InternalSetIsCacheFresh = (ctx.CacheFreshnessStatus != CacheFreshnessStatus.Stale);
                ProcessResponse(); 
                return true;
            } 
            catch (Exception exception) 
            {
                Abort(exception, AbortState.Public); 
                throw;
            }
        }
 
        //
        // This method has to be invoked as part of the wire response processing. 
        // The wire response can be replaced on return 
        //
        // ATTN: If the method returns false, the response is invalid and should be retried 
        //
        private bool CheckCacheRetrieveOnResponse() {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheRetrieveOnResponse");
 
            if (CacheProtocol == null) {
                return true; 
            } 

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) { 
                throw CacheProtocol.ProtocolException;
            }

            Stream oldResponseStream = _HttpResponse.ResponseStream; 

            CacheProtocol.GetRevalidateStatus(_HttpResponse, _HttpResponse.ResponseStream); 
 
            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer)
            { 
                // Try to resubmit or fail
                return false;
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse &&
                CacheProtocol.ProtocolStatus != CacheValidationStatus.CombineCachedAndServerResponse) 
            { 
                // Take current response
                return true; 
            }

            if (HttpWriteMode!=HttpWriteMode.None) {
                // This should never happen in real life 
                throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_body));
            } 
 
            CoreResponseData responseData = new CoreResponseData();
            HttpRequestCacheValidator ctx = (HttpRequestCacheValidator) CacheProtocol.Validator; 
            // If we take it from cache, we have to replace the live response if any
            responseData.m_IsVersionHttp11  = ctx.CacheHttpVersion.Equals(HttpVersion.Version11);
            responseData.m_StatusCode       = ctx.CacheStatusCode;
            responseData.m_StatusDescription= ctx.CacheStatusDescription; 

            responseData.m_ResponseHeaders  = CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse 
                                                ? new WebHeaderCollection(ctx.CacheHeaders) 
                                                : ctx.CacheHeaders;
 
            responseData.m_ContentLength    = CacheProtocol.ResponseStreamLength;
            responseData.m_ConnectStream    = CacheProtocol.ResponseStream;

            _HttpResponse = new HttpWebResponse(_Uri, CurrentMethod, responseData, _MediaType, UsesProxySemantics, AutomaticDecompression); 

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.ReturnCachedResponse) 
            { 
                _HttpResponse.InternalSetFromCache = true;
                _HttpResponse.InternalSetIsCacheFresh = CacheProtocol.IsCacheFresh; 

                // can only dispose the response stream when not combining the streams
                // Note the response itself may still be needed for cache update call.
                if (oldResponseStream != null) 
                {
                    try { 
                        oldResponseStream.Close(); 
                    }
                    catch { 
                    }
                }
            }
            return true; 
        }
 
        // 
        // This will decide on cache update and construct the effective response
        // 
        // Possible CacheStatus on Input:
        // - Bypass     = exit from the method, now
        // - FromCache  = Take from cache, do not update the headers (see Bypass))
        // - Proceed    = Take the cached response, ask for cache Context update 
        // - NoCache    = Take the live response, ask for cache update
        // 
        private void CheckCacheUpdateOnResponse() { 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheUpdateOnResponse");
 
            if (CacheProtocol == null) {
                return;
            }
 
            if (CacheProtocol.GetUpdateStatus(_HttpResponse, _HttpResponse.ResponseStream) == CacheValidationStatus.UpdateResponseInformation)
            { 
                _HttpResponse.ResponseStream = CacheProtocol.ResponseStream; 
            }
            else if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) 
                throw CacheProtocol.ProtocolException;
        }

        /*++ 

        EndSubmitRequest: End Submit off a request 
 
        This function is invoked by a connection ready callback and continues the request by submitting its headers.
 
        --*/
        private void EndSubmitRequest()
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest"); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest");
 
            try { 

                // 
                // check to see if we need to buffer the headers and send them at
                // a later time, when we know content length
                //
                if (HttpWriteMode==HttpWriteMode.Buffer) { 
                    InvokeGetRequestStreamCallback();
                    GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest", "InvokeGetRequestStreamCallback(HttpWriteMode==HttpWriteMode.Buffer)"); 
                    return; 
                }
 
                // gather header bytes and write them to the stream
                if (WriteBuffer==null)
                {
                    long result = SwitchToContentLength(); 
                    SerializeHeaders();
                    PostSwitchToContentLength(result); 
                } 

                GlobalLog.Assert(WriteBuffer != null && WriteBuffer[0] < 0x80 && WriteBuffer[0] != 0x0, "HttpWebRequest#{0}::EndSubmitRequest()|Invalid WriteBuffer generated.", ValidationHelper.HashString(this)); 

                _SubmitWriteStream.WriteHeaders(Async);
            }
            catch { 
                // We depend on this to unblock possible response processing in case of unexpected failure
                ConnectStream chkStream = _SubmitWriteStream; 
                if (chkStream != null) 
                    chkStream.CallDone();
 
                throw;
            }
            finally {
                if (!Async) 
                    CheckWriteSideResponseProcessing();
            } 
 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndSubmitRequest");
        } 


        /*++
 
            EndWriteHeaders: End write of headers
 
            This Typically called by a callback that wishes to proceed 
             with the finalization of writing headers
 
            Input: Nothing.

            Returns: bool - true if success, false if we need to go pending
 
        --*/
        internal bool EndWriteHeaders(bool async) 
        { 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders async:" + async.ToString());
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders"); 

            try {
                //
                // if sending data and we sent a 100-continue to a 1.1 or better 
                // server then synchronize with the 100-continue intermediate
                // response (or a final failure response) 
                // 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders() ContentLength:" + ContentLength + " HttpWriteMode:" + HttpWriteMode + " _ServicePoint.Understands100Continue:" + _ServicePoint.Understands100Continue + " ExpectContinue:" + ExpectContinue);
                if ((ContentLength>0 || HttpWriteMode==HttpWriteMode.Chunked) && ExpectContinue && _ServicePoint.Understands100Continue) { 
                    if (async ? m_ContinueGate.StartTrigger(true) : m_ContinueGate.Trigger(true))
                    {
                        if (async)
                        { 
                            try
                            { 
                                // If we haven't already received the continue, set a timer. 
                                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders() starting timer for 100Continue, timeout:" + DefaultContinueTimeout.ToString());
                                GlobalLog.Assert(m_ContinueTimer == null, "HttpWebRequest#{0}::EndWriteHeaders()|Timer already set.", ValidationHelper.HashString(this)); 
                                m_ContinueTimer = s_ContinueTimerQueue.CreateTimer(s_ContinueTimeoutCallback, this);
                            }
                            finally
                            { 
                                m_ContinueGate.FinishTrigger();
                            } 
 
                            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders", false);
                            return false; 
                        }
                        else {
                            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders() calling PollAndRead()");
                            // On the Sync Path, we need to poll the Connection to see if there is any Data 
                            _SubmitWriteStream.PollAndRead(UserRetrievedWriteStream);
                            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders", true); 
                            return true; 
                        }
                    } 
                }

                // No continue expected or it was already received.  Move forward.
                EndWriteHeaders_Part2(); 
            }
            catch { 
                // We depend on this to unblock possible response processing in case of unexpected failure 
                ConnectStream chkStream = _SubmitWriteStream;
                if (chkStream != null) 
                    chkStream.CallDone();

                throw;
            } 

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders", true); 
            return true; 
        }
 
        // This can never call into user code or block, because it's called by the TimerThread.
        private static void ContinueTimeoutCallback(TimerThread.Timer timer, int timeNoticed, object context)
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(context) + "::ContinueTimeoutCallback"); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, ThreadKinds.SafeSources | ThreadKinds.Timer, "HttpWebRequest#" + ValidationHelper.HashString(context) + "::ContinueTimeoutCallback");
 
            HttpWebRequest thisHttpWebRequest = (HttpWebRequest) context; 

            if (thisHttpWebRequest.HttpWriteMode == HttpWriteMode.None) 
            {
                GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(thisHttpWebRequest) + "::CompleteContinueGate()", "Not a POST type request, must not come here.");
                return;
            } 

            // Complete the 100 Continue gate.  If this completes it, clean up the timer. 
            if (thisHttpWebRequest.CompleteContinueGate()) 
            {
                GlobalLog.Assert(thisHttpWebRequest.m_ContinueTimer == timer, "HttpWebRequest#{0}::ContinueTimeoutCallback|Timers don't match.", ValidationHelper.HashString(thisHttpWebRequest)); 
                thisHttpWebRequest.m_ContinueTimer = null;
            }

            // Always call this.  Otherwise the timer should have been successfully cancelled. 
            //
            // We have to put it on a threadpool thread since it may call user code.  This is not 
            // a critical path for perf. 
            ThreadPool.UnsafeQueueUserWorkItem(s_EndWriteHeaders_Part2Callback, thisHttpWebRequest);
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(thisHttpWebRequest) + "::ContinueTimeoutCallback"); 
        }

        // This has to be an instance method because otherwise:
        // 
        // 1>d:\ncl\whidbey_xws\ndp\fx\src\net\system\net\httpwebrequest.cs(3186,17) : erro
        // r CS1690: Cannot call methods, properties, or indexers on 'System.Net.HttpWebReq 
        // uest.m_ContinueGate' because it is a value type member of a marshal-by-reference 
        // class
        private bool CompleteContinueGate() 
        {
            return m_ContinueGate.Complete();
        }
        private static void EndWriteHeaders_Part2Wrapper(object state) 
        {
#if DEBUG 
            GlobalLog.SetThreadSource(ThreadKinds.Worker); 
            using (GlobalLog.SetThreadKind(ThreadKinds.System)) {
#endif 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(state) + "::EndWriteHeaders_Part2Wrapper");
            ((HttpWebRequest)state).EndWriteHeaders_Part2();
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(state) + "::EndWriteHeaders_Part2Wrapper");
#if DEBUG 
            }
#endif 
        } 

        internal void EndWriteHeaders_Part2() 
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2");
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2");
 
            try {
                ConnectStream submitWriteStream = _SubmitWriteStream; 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() ConnectStream#" + ValidationHelper.HashString(submitWriteStream) + " HttpWriteMode:" + HttpWriteMode + " HaveResponse:" + HaveResponse); 
                if (HttpWriteMode != HttpWriteMode.None)
                { 
                    m_BodyStarted = true;

                    GlobalLog.Assert(submitWriteStream != null, "HttpWebRequest#{0}::EndWriteHeaders_Part2()|submitWriteStream == null", ValidationHelper.HashString(this));
                    // 
                    // We always need to buffer because some servers send
                    // 100 Continue even when they mean to redirect, 
                    // so we waste the cycles with buffering 
                    //
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() AllowWriteStreamBuffering:" + AllowWriteStreamBuffering); 
                    if (AllowWriteStreamBuffering) {
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() BufferOnly:" + submitWriteStream.BufferOnly + " _OldSubmitWriteStream#" + ValidationHelper.HashString(_OldSubmitWriteStream) + " submitWriteStream#" + ValidationHelper.HashString(submitWriteStream));
                        if (submitWriteStream.BufferOnly) {
                            // 
                            // if the ConnectStream was buffering the headers then
                            // there will not be an OldSubmitWriteStream. set it 
                            // now to the newly created one. 
                            //
                            _OldSubmitWriteStream = submitWriteStream; 
                        }
                        if (_OldSubmitWriteStream != null)
                        {
                            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2() _OldSubmitWriteStream#" + ValidationHelper.HashString(_OldSubmitWriteStream) + " NtlmKeepAlive:" + NtlmKeepAlive); 
                            // workaround for NTLM: we're submitting this as ContentLength 0
                            // We need a second check for a buffering-only POST case. 
                            // 
    #if DEBUG
                            using (GlobalLog.SetThreadKind(ThreadKinds.Sync)) { 
    #endif
                            submitWriteStream.ResubmitWrite(_OldSubmitWriteStream, (NtlmKeepAlive && ContentLength == 0));
    #if DEBUG
                            } 
    #endif
                            submitWriteStream.CloseInternal(true); 
                        } 
                    }
                } 
                else { // if (HttpWriteMode == HttpWriteMode.None) {
                    if (submitWriteStream != null) {
                        // close stream so the headers get sent
                        submitWriteStream.CloseInternal(true); 
                        // disable write stream
                        submitWriteStream = null; 
                    } 
                    _OldSubmitWriteStream = null;
                } 

                // callback processing - notify our caller that we're done
                InvokeGetRequestStreamCallback();
            } 
            catch {
                // We depend on this to unblock possible response processing in case of unexpected failure 
                ConnectStream chkStream = _SubmitWriteStream; 
                if (chkStream != null)
                    chkStream.CallDone(); 

                //
                // Here we don't expect any exceptions and if got some from the user code then propagate it up.
                // 
                throw;
            } 
 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndWriteHeaders_Part2");
        } 

        /*++

        Routine Description: 

            Assembles the status line for an HTTP request 
             specifically for CONNECT style verbs, that create a pipe 

        Arguments: 

            headersSize - size of the Header string that we send after
                this request line
 
        Return Value:
 
            int - number of bytes written out 

        --*/ 
        private int GenerateConnectRequestLine(int headersSize) {
            int offset = 0;

            HostHeaderString host = new HostHeaderString(HostAndPort(true)); 

            // 
            // Handle Connect Case, i.e. "CONNECT hostname.domain.edu:999" 
            //
 
            int writeBufferLength = CurrentMethod.Name.Length +
                                    host.ByteCount +
                                    RequestLineConstantSize +
                                    headersSize; 
            _WriteBuffer = new byte[writeBufferLength];
            offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0); 
            WriteBuffer[offset++] = (byte)' '; 
            host.Copy(WriteBuffer, offset);
            offset += host.ByteCount; 
            WriteBuffer[offset++] = (byte)' ';
            return offset;
        }
 
        internal string HostAndPort(bool addDefaultPort) {
            Uri UriToUse; 
            if (IsTunnelRequest) { 
                UriToUse = _OriginUri;
            } else { 
                UriToUse = _Uri;
            }
            String HostToUse;
            if (UriToUse.HostNameType == UriHostNameType.IPv6) { 
                // if IPv6 literal then remove any scope ID & add brackets
                HostToUse = "[" + TrimScopeID(UriToUse.DnsSafeHost) + "]"; 
            } else { 
                HostToUse = UriToUse.DnsSafeHost;
            } 
            if (addDefaultPort || !UriToUse.IsDefaultPort) {
                return HostToUse + ":" + UriToUse.Port;
            } else {
                return HostToUse; 
            }
        } 
 
        private string TrimScopeID(string s) {
            int i = s.LastIndexOf('%'); 
            if (i > 0)
                return s.Substring(0,i);
            return s;
        } 

        /*++ 
 
        Routine Description:
 
            Assembles the status line for an HTTP request
             specifically to a proxy...

        Arguments: 

            headersSize - size of the Header string that we send after 
                this request line 

        Return Value: 

            int - number of bytes written out

        --*/ 
        private int GenerateProxyRequestLine(int headersSize) {
            // 
            // Handle Proxy Case, i.e. "GET http://hostname-outside-of-proxy.somedomain.edu:999" 
            // consider handling other schemes
            // 
            // Note that we will take the scheme off the URI, hence may issue other but http request
            // through the proxy on redirect. While this is not allowed by RFC,
            // this it used to work in IE and we have already tested permissions for that destination Uri.
            if ((object)_Uri.Scheme == (object)Uri.UriSchemeFtp) { 
                // FTP
                return GenerateFtpProxyRequestLine(headersSize); 
            } 
            // HTTP
            int offset = 0; 
            string scheme = _Uri.GetComponents(UriComponents.Scheme | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
            HostHeaderString host = new HostHeaderString(HostAndPort(false));
            string path = _Uri.GetComponents(UriComponents.Path | UriComponents.Query, UriFormat.UriEscaped);
 
            int writeBufferLength = CurrentMethod.Name.Length +
                                    scheme.Length + 
                                    host.ByteCount + 
                                    path.Length +
                                    RequestLineConstantSize + 
                                    headersSize;
            _WriteBuffer = new byte[writeBufferLength];

            offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0); 
            WriteBuffer[offset++] = (byte)' ';
            offset += Encoding.ASCII.GetBytes(scheme, 0, scheme.Length, WriteBuffer, offset); 
            host.Copy(WriteBuffer, offset); 
            offset += host.ByteCount;
            offset += Encoding.ASCII.GetBytes(path, 0, path.Length, WriteBuffer, offset); 
            WriteBuffer[offset++] = (byte)' ';
            return offset;
        }
 
        private int GenerateFtpProxyRequestLine(int headersSize) {
            // Special handling for FTP via HTTP proxy 
            int offset = 0; 
            string scheme = _Uri.GetComponents(UriComponents.Scheme | UriComponents.KeepDelimiter, UriFormat.UriEscaped);
            string userInfo = _Uri.GetComponents(UriComponents.UserInfo | UriComponents.KeepDelimiter, UriFormat.UriEscaped); 
            HostHeaderString host = new HostHeaderString(HostAndPort(false));
            string path = _Uri.GetComponents(UriComponents.Path | UriComponents.Query, UriFormat.UriEscaped);

            if (userInfo == "") { 
                // No userinfo so see if we can add from Credentials
                string username = null; 
                string password = null; 
                NetworkCredential networkCreds = Credentials.GetCredential(_Uri, "basic");
                if (networkCreds != null 
                    && (object)networkCreds
                       != (object)FtpWebRequest.DefaultNetworkCredential)
                {
                    username = networkCreds.InternalGetDomainUserName(); 
                    password = networkCreds.InternalGetPassword();
                    password = (password == null) ? string.Empty : password; 
                } 
                if (username != null) {
                    // For FTP proxy we don't escape the username and password strings 
                    // Since some servers don't seem to support it
                    // Only escape the absolute minimum that is required for
                    // a valid Uri which is (: \ / ? # %)
                    username = username.Replace(":",  "%3A"); 
                    password = password.Replace(":",  "%3A");
                    username = username.Replace("\\", "%5C"); 
                    password = password.Replace("\\", "%5C"); 
                    username = username.Replace("/",  "%2F");
                    password = password.Replace("/",  "%2F"); 
                    username = username.Replace("?",  "%3F");
                    password = password.Replace("?",  "%3F");
                    username = username.Replace("#",  "%23");
                    password = password.Replace("#",  "%23"); 
                    username = username.Replace("%",  "%25");
                    password = password.Replace("%",  "%25"); 
                    username = username.Replace("@",  "%40"); 
                    password = password.Replace("@",  "%40");
 
                    // build complete userinfo
                    userInfo = username + ":" + password + "@";
                }
            } 

            // construct request line from components 
            int writeBufferLength = CurrentMethod.Name.Length + 
                                    scheme.Length +
                                    userInfo.Length + 
                                    host.ByteCount +
                                    path.Length +
                                    RequestLineConstantSize +
                                    headersSize; 
            _WriteBuffer = new byte[writeBufferLength];
 
            offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0); 
            WriteBuffer[offset++] = (byte)' ';
            offset += Encoding.ASCII.GetBytes(scheme, 0, scheme.Length, WriteBuffer, offset); 
            offset += Encoding.ASCII.GetBytes(userInfo, 0, userInfo.Length, WriteBuffer, offset);
            host.Copy(WriteBuffer, offset);
            offset += host.ByteCount;
            offset += Encoding.ASCII.GetBytes(path, 0, path.Length, WriteBuffer, offset); 
            WriteBuffer[offset++] = (byte)' ';
            return offset; 
        } 

        /*++ 

        Routine Description:

            Assembles the status/request line for the request. 

        Arguments: 
 
            headersSize - size of the Header string that we send after
                this request line 

        Return Value:

            int - number of bytes written 

        --*/ 
        private int GenerateRequestLine(int headersSize) { 
            int offset = 0;
            string pathAndQuery = _Uri.PathAndQuery; 

            int writeBufferLength =
                CurrentMethod.Name.Length +
                pathAndQuery.Length + 
                RequestLineConstantSize +
                headersSize; 
 
            _WriteBuffer = new byte[writeBufferLength];
            offset = Encoding.ASCII.GetBytes(CurrentMethod.Name, 0, CurrentMethod.Name.Length, WriteBuffer, 0); 
            WriteBuffer[offset++] = (byte)' ';
            offset += Encoding.ASCII.GetBytes(pathAndQuery, 0, pathAndQuery.Length, WriteBuffer, offset);
            WriteBuffer[offset++] = (byte)' ';
            return offset; 
        }
 
        /*++ 

        Routine Description: 

            Assembles the data/headers for an HTTP request
             into a buffer
 
        Arguments:
 
            none. 

        Return Value: 

            none.

        --*/ 
        internal void UpdateHeaders() {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders"); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders"); 

#if TRAVE 
            _HttpRequestHeaders.Set("Cur-Hash-ID", ValidationHelper.HashString(this));
            _HttpRequestHeaders.AddInternal("Hash-ID", ValidationHelper.HashString(this));
#endif
            // Set HostName Header 
            // Do unusual encoding so that host header value gets serialized to wire properly
            HostHeaderString hhs = new HostHeaderString(HostAndPort(false)); 
            string host = WebHeaderCollection.HeaderEncoding.GetString(hhs.Bytes, 0, hhs.ByteCount); 
            _HttpRequestHeaders.ChangeInternal( HttpKnownHeaderNames.Host, host);
            // about to create the headers we're going to send. Check if any 
            // modules want to inspect or modify them
            if (_CookieContainer != null) {
                CookieModule.OnSendingHeaders(this);
            } 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders");
        } 
 
        //
        // The method is called right before sending headers to the wire 
        // The result is updated internal _WriteBuffer
        //
        internal void SerializeHeaders() {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::UpdateHeaders"); 

            // 
            // If we have content-length, use it, if we don't check for chunked 
            //  sending mode, otherwise, if -1, then see to closing the connection.
            // There's one extra case in which the user didn't set the ContentLength and is 
            //  not chunking either. In this case we buffer the data, but to the time of that
            //  method call the content length is already known.
            //
            GlobalLog.Assert(HttpWriteMode!=HttpWriteMode.Unknown, "HttpWebRequest#{0}::SerializeHeaders()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode); 
            if (HttpWriteMode!=HttpWriteMode.None) {
                if (HttpWriteMode==HttpWriteMode.Chunked) { 
                    GlobalLog.Assert(!CurrentMethod.ContentBodyNotAllowed, "HttpWebRequest#{0}::SerializeHeaders()|!ContentBodyNotAllowed CurrentMethod:{1} HttpWriteMode:{2} ContentLength:{3}", ValidationHelper.HashString(this), CurrentMethod, HttpWriteMode, ContentLength); 
                    _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.TransferEncoding, ChunkedHeader);
                } 
                else if (ContentLength>=0) {
                    GlobalLog.Assert(HttpWriteMode == HttpWriteMode.ContentLength, "HttpWebRequest#{0}::SerializeHeaders()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode);
                    GlobalLog.Assert(!CurrentMethod.ContentBodyNotAllowed, "HttpWebRequest#{0}::SerializeHeaders()|!ContentBodyNotAllowed CurrentMethod:{1} HttpWriteMode:{2} ContentLength:{3}", ValidationHelper.HashString(this), CurrentMethod, HttpWriteMode, ContentLength);
                    _HttpRequestHeaders.ChangeInternal(HttpKnownHeaderNames.ContentLength, _ContentLength.ToString(NumberFormatInfo.InvariantInfo)); 
                }
                ExpectContinue = ExpectContinue && !IsVersionHttp10 && ServicePoint.Expect100Continue; 
                if ((ContentLength>0 || HttpWriteMode==HttpWriteMode.Chunked) && ExpectContinue) { 
                    _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.Expect, ContinueHeader);
                } 
            }

            if((AutomaticDecompression & DecompressionMethods.GZip) != 0){
 
                if((AutomaticDecompression & DecompressionMethods.Deflate) != 0){
                    _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.AcceptEncoding, GZipHeader + ", " + DeflateHeader); 
                } 
                else{
                    _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.AcceptEncoding, GZipHeader); 
                }
            }
            else if((AutomaticDecompression & DecompressionMethods.Deflate) != 0){
                _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.AcceptEncoding, DeflateHeader); 
            }
 
            // 
            // Behavior from Wininet, on Uris with Proxies, send Proxy-Connection: instead
            //  of Connection: 
            //
            //QFE 4599: ServicePoint for SSL Tunnel through proxy is not
            //deemed as a proxy service point in v2.0 due to proxy changes.
            //We are doing a surgical fix for the QFE purposes 
            //For HAWAII we need to redefine what it means to use a
            //proxy service point properly 
            string connectionString = HttpKnownHeaderNames.Connection; 
            if (UsesProxySemantics || IsTunnelRequest ) {
                _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Connection); 
                connectionString = HttpKnownHeaderNames.ProxyConnection;
                if (!ValidationHelper.IsBlankString(Connection)) {
                    _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.ProxyConnection, _HttpRequestHeaders[HttpKnownHeaderNames.Connection]);
                } 
            }
            else { 
                _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ProxyConnection); 
            }
 
            if (KeepAlive || NtlmKeepAlive) {
                GlobalLog.Assert(_ServicePoint != null, "HttpWebRequest#{0}::SerializeHeaders()|_ServicePoint == null", ValidationHelper.HashString(this));
                if (IsVersionHttp10 || ServicePoint.HttpBehaviour<=HttpBehaviour.HTTP10) {
                    _HttpRequestHeaders.AddInternal(( (UsesProxySemantics  || IsTunnelRequest)? HttpKnownHeaderNames.ProxyConnection : HttpKnownHeaderNames.Connection), "Keep-Alive"); 
                }
            } 
            else if (!IsVersionHttp10) { 
                _HttpRequestHeaders.AddInternal(connectionString, "Close");
            } 


            //
            // Now create our headers by calling ToString, and then 
            //   create a HTTP Request Line to go with it.
            // 
 
            int offset;
            string requestHeadersString = _HttpRequestHeaders.ToString(); 
            int requestHeadersSize = WebHeaderCollection.HeaderEncoding.GetByteCount(requestHeadersString);

            // NOTE: Perhaps we should cache this on this-object in the future?
            if (CurrentMethod.ConnectRequest) { 
                // for connect verbs we need to specially handle it.
                offset = GenerateConnectRequestLine(requestHeadersSize); 
            } 
            else if (UsesProxySemantics) {
                // depending on whether, we have a proxy, generate a proxy or normal request 
                offset = GenerateProxyRequestLine(requestHeadersSize);
            }
            else {
                // default case for normal HTTP requests 
                offset = GenerateRequestLine(requestHeadersSize);
            } 
 
            Buffer.BlockCopy(HttpBytes, 0, WriteBuffer, offset, HttpBytes.Length);
            offset += HttpBytes.Length; 

            WriteBuffer[offset++] = (byte)'1';
            WriteBuffer[offset++] = (byte)'.';
            WriteBuffer[offset++] = IsVersionHttp10 ? (byte)'0' : (byte)'1'; 
            WriteBuffer[offset++] = (byte)'\r';
            WriteBuffer[offset++] = (byte)'\n'; 
            if (Logging.On) Logging.PrintInfo(Logging.Web, this, "Request: "+Encoding.ASCII.GetString(WriteBuffer, 0, offset)); 
            //
            // Serialze the headers out to the byte Buffer, 
            //   by converting them to bytes from UNICODE
            //
            WebHeaderCollection.HeaderEncoding.GetBytes(requestHeadersString, 0, requestHeadersString.Length, WriteBuffer, offset);
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SerializeHeaders(), bytesCount = " + offset.ToString()); 
        }
 
 
        //
        // PERF: 
        // removed some double initializations.
        // perf went from:
        // clocks per instruction CPI: 9,098.72 to 1,301.14
        // %app exclusive time: 2.92 to 0.43 
        //
        ///  
        ///     
        ///       Basic Constructor for HTTP Protocol Class, Initializes to basic header state.
        ///     
        /// 
        internal HttpWebRequest(Uri uri, ServicePoint servicePoint) {
            if(Logging.On)Logging.Enter(Logging.Web, this, "HttpWebRequest", uri);
 
            (new WebPermission(NetworkAccess.Connect, uri)).Demand();
 
            // OOPS, This ctor can also be called with FTP scheme but then it should only allowed if going through the proxy 
            // Something to think about...
            //if ((object)uri.Scheme != (object)Uri.UriSchemeHttp && (object)uri.Scheme != (object)Uri.UriSchemeHttps) 
                //throw new ArgumentOutOfRangeException("uri");

            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::.ctor(" + uri.ToString() + ")");
            // 
            // internal constructor, HttpWebRequest cannot be created directly
            // but only through WebRequest.Create() method 
            // set defaults 
            //
            _HttpRequestHeaders         = new WebHeaderCollection(WebHeaderCollectionType.HttpWebRequest); 
            _Proxy                      = WebRequest.InternalDefaultWebProxy;
            _HttpWriteMode              = HttpWriteMode.Unknown;
            _MaximumAllowedRedirections = 50;
            _Timeout                    = WebRequest.DefaultTimeout; 
            _TimerQueue                 = WebRequest.DefaultTimerQueue;
            _ReadWriteTimeout           = DefaultReadWriteTimeout; 
            _MaximumResponseHeadersLength = DefaultMaximumResponseHeadersLength; 
            _ContentLength              = -1;
            _OriginVerb                 = KnownHttpVerb.Get; 
            _OriginUri                  = uri;
            _Uri                        = _OriginUri;
            _ServicePoint               = servicePoint;
            _RequestIsAsync             = TriState.Unspecified; 

            SetupCacheProtocol(_OriginUri); 
 
#if HTTP_HEADER_EXTENSIONS_SUPPORTED
            _NextExtension      = 10; 
#endif // HTTP_HEADER_EXTENSIONS_SUPPORTED

            if(Logging.On)Logging.Exit(Logging.Web, this, "HttpWebRequest", null);
        } 

        internal HttpWebRequest(Uri proxyUri, Uri requestUri, HttpWebRequest orginalRequest) : this(proxyUri, null) { 
 
            GlobalLog.Enter("HttpWebRequest::HttpWebRequest",
                            "proxyUri="+proxyUri+", requestUri="+requestUri 
                            );

            _OriginVerb = KnownHttpVerb.Parse("CONNECT");
 
            //
            // CONNECT requests cannot be pipelined 
            // 

            Pipelined = false; 

            //
            // each CONNECT request has a unique connection group name to avoid
            // non-CONNECT requests being made over the same connection 
            //
 
            _OriginUri = requestUri; 
            IsTunnelRequest = true;
 
            _ConnectionGroupName = ServicePointManager.SpecialConnectGroupName + "(" + UniqueGroupId + ")";
            m_InternalConnectionGroup = true;

            // 
            // the CONNECT request must respond to a 407 as if it were a 401.
            // So we set up the server authentication state as if for a proxy 
            // 
            ServerAuthenticationState = new AuthenticationState(true);
 
            // CONNECT request is not suitable for caching
            CacheProtocol = null;

            GlobalLog.Leave("HttpWebRequest::HttpWebRequest"); 
        }
 
        ///  
        ///    ISerializable constructor
        ///  
        [Obsolete("Serialization is obsoleted for this type.  http://go.microsoft.com/fwlink/?linkid=14202")]
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter =true)]
        /*private*/ protected HttpWebRequest(SerializationInfo serializationInfo, StreamingContext streamingContext):base(serializationInfo, streamingContext) {
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
#endif 
            ExceptionHelper.WebPermissionUnrestricted.Demand(); 
            if(Logging.On)Logging.Enter(Logging.Web, this, "HttpWebRequest", serializationInfo);
 
            _HttpRequestHeaders         = (WebHeaderCollection)serializationInfo.GetValue("_HttpRequestHeaders", typeof(WebHeaderCollection));
            _Proxy                      = (IWebProxy)serializationInfo.GetValue("_Proxy", typeof(IWebProxy));
            KeepAlive                   = serializationInfo.GetBoolean("_KeepAlive");
            Pipelined                   = serializationInfo.GetBoolean("_Pipelined"); 
            AllowAutoRedirect           = serializationInfo.GetBoolean("_AllowAutoRedirect");
            AllowWriteStreamBuffering   = serializationInfo.GetBoolean("_AllowWriteStreamBuffering"); 
            HttpWriteMode               = (HttpWriteMode)serializationInfo.GetInt32("_HttpWriteMode"); 
            _MaximumAllowedRedirections = serializationInfo.GetInt32("_MaximumAllowedRedirections");
            _AutoRedirects              = serializationInfo.GetInt32("_AutoRedirects"); 
            _Timeout                    = serializationInfo.GetInt32("_Timeout");
            try {
                _ReadWriteTimeout       = serializationInfo.GetInt32("_ReadWriteTimeout");
            } 
            catch {
                _ReadWriteTimeout       = DefaultReadWriteTimeout; 
            } 
            try {
                _MaximumResponseHeadersLength = serializationInfo.GetInt32("_MaximumResponseHeadersLength"); 
            }
            catch {
                _MaximumResponseHeadersLength = DefaultMaximumResponseHeadersLength;
            } 
            _ContentLength              = serializationInfo.GetInt64("_ContentLength");
            _MediaType                  = serializationInfo.GetString("_MediaType"); 
            _OriginVerb                 = KnownHttpVerb.Parse(serializationInfo.GetString("_OriginVerb")); 
            _ConnectionGroupName        = serializationInfo.GetString("_ConnectionGroupName");
            ProtocolVersion             = (Version)serializationInfo.GetValue("_Version", typeof(Version)); 
            _OriginUri                  = (Uri)serializationInfo.GetValue("_OriginUri", typeof(Uri));
#if HTTP_HEADER_EXTENSIONS_SUPPORTED
            _NextExtension              = serializationInfo.GetInt32("_NextExtension");
#endif // HTTP_HEADER_EXTENSIONS_SUPPORTED 

            SetupCacheProtocol(_OriginUri); 
            if(Logging.On)Logging.Exit(Logging.Web, this, "HttpWebRequest", null); 
#if DEBUG
            } 
#endif
        }

        ///  
        ///    ISerializable method
        ///  
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)] 
        void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        { 
#if DEBUG
            using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
#endif
            GetObjectData(serializationInfo, streamingContext); 
#if DEBUG
            } 
#endif 
        }
 
        //
        // FxCop: Need this in addition to the above in order to allow derived classes to access the base implementation.
        //
        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter =true)] 
        protected override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
        { 
#if DEBUG 
            using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
#endif 
            //
            // for now disregard streamingContext.
            // just Add all the members we need to deserialize to construct
            // the object at deserialization time 
            //
            // the following runtime types already support serialization: 
            // Boolean, Char, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, DateTime 
            // for the others we need to provide our own serialization
            // 
            serializationInfo.AddValue("_HttpRequestHeaders", _HttpRequestHeaders, typeof(WebHeaderCollection));
            serializationInfo.AddValue("_Proxy", _Proxy, typeof(IWebProxy));
            serializationInfo.AddValue("_KeepAlive", KeepAlive);
            serializationInfo.AddValue("_Pipelined", Pipelined); 
            serializationInfo.AddValue("_AllowAutoRedirect", AllowAutoRedirect);
            serializationInfo.AddValue("_AllowWriteStreamBuffering", AllowWriteStreamBuffering); 
            serializationInfo.AddValue("_HttpWriteMode", HttpWriteMode); 
            serializationInfo.AddValue("_MaximumAllowedRedirections", _MaximumAllowedRedirections);
            serializationInfo.AddValue("_AutoRedirects", _AutoRedirects); 
            serializationInfo.AddValue("_Timeout", _Timeout);
            serializationInfo.AddValue("_ReadWriteTimeout", _ReadWriteTimeout);
            serializationInfo.AddValue("_MaximumResponseHeadersLength", _MaximumResponseHeadersLength);
            serializationInfo.AddValue("_ContentLength", ContentLength); 
            serializationInfo.AddValue("_MediaType", _MediaType);
            serializationInfo.AddValue("_OriginVerb", _OriginVerb); 
            serializationInfo.AddValue("_ConnectionGroupName", _ConnectionGroupName); 
            serializationInfo.AddValue("_Version", ProtocolVersion, typeof(Version));
            serializationInfo.AddValue("_OriginUri", _OriginUri, typeof(Uri)); 
#if HTTP_HEADER_EXTENSIONS_SUPPORTED
            serializationInfo.AddValue("_NextExtension", _NextExtension);
#endif // HTTP_HEADER_EXTENSIONS_SUPPORTED
            base.GetObjectData(serializationInfo, streamingContext); 
#if DEBUG
            } 
#endif 
        }
 
        /// 
        ///    Used by ServicePoint code to find the right connection Group
        /// 
        internal static StringBuilder GenerateConnectionGroup(string connectionGroupName, bool unsafeConnectionGroup, bool isInternalGroup) { 
            StringBuilder connectionLine = new StringBuilder(connectionGroupName);
 
            connectionLine.Append(unsafeConnectionGroup ? "U>" : "S>"); 

            if (isInternalGroup) 
            {
                connectionLine.Append("I>");
            }
 
            return connectionLine;
        } 
 

        ///  
        ///    Generates a string that
        ///     allows a Connection to remain unique for a given NTLM auth
        ///     user, this is needed to prevent multiple users from
        ///     using the same sockets after they are authenticated. 
        /// 
        internal string GetConnectionGroupLine() { 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetConnectionGroupLine"); 
            StringBuilder connectionLine = GenerateConnectionGroup(_ConnectionGroupName, UnsafeAuthenticatedConnectionSharing, m_InternalConnectionGroup);
 
            // consider revisting this looking into how this would work,
            // if we were doing auth through both proxy and server,
            // I belive this can't work in any case, so we're okay.
 
            //
            // for schemes of ssl, we need to create a special connection group 
            //  otherwise, we'll try sharing proxy connections across SSL servers 
            //  which won't work.
            // 

            if ((_Uri.Scheme == Uri.UriSchemeHttps) || IsTunnelRequest) {
                if (UsesProxy) {
                    connectionLine.Append(HostAndPort(true)); 
                    connectionLine.Append("$");
                } 
#if !FEATURE_PAL 
                if (_ClientCertificates!=null && ClientCertificates.Count>0) {
                    connectionLine.Append(ClientCertificates.GetHashCode().ToString(NumberFormatInfo.InvariantInfo)); 
                }
#endif //!FEATURE_PAL
            }
            if (ProxyAuthenticationState.UniqueGroupId != null) { 
                connectionLine.Append(ProxyAuthenticationState.UniqueGroupId);
            } 
            else if (ServerAuthenticationState.UniqueGroupId != null) { 
                connectionLine.Append(ServerAuthenticationState.UniqueGroupId);
            } 

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetConnectionGroupLine", connectionLine.ToString());
            return connectionLine.ToString();
        } 

 
        ///  
        ///    CheckResubmitForAuth - Determines if a HTTP request needs to be
        ///     resubmitted due to HTTP authenication 
        ///
        ///     true  - if we should reattempt submitting the request
        ///     false - if the request is complete
        ///      
        /// 
        private bool CheckResubmitForAuth() { 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth"); 
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth");
 

            bool result = false;
            bool authenticated = false;
            bool skip = false; 
            if (UsesProxySemantics && _Proxy != null && _Proxy.Credentials!=null) {
                try 
                { 
                    result |= ProxyAuthenticationState.AttemptAuthenticate(this, _Proxy.Credentials);
                } 
                catch (Win32Exception)
                {
                    if (!m_Extra401Retry)
                    { 
                        throw;
                    } 
                    skip = true; 
                }
                authenticated = true; 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth() ProxyAuthenticationState.AttemptAuthenticate() returns result:" + result.ToString());
            }
            if (Credentials != null && !skip)
            { 
                try
                { 
                    result |= ServerAuthenticationState.AttemptAuthenticate(this, Credentials); 
                }
                catch (Win32Exception) 
                {
                    if (!m_Extra401Retry)
                    {
                        throw; 
                    }
                    result = false; 
                } 
                authenticated = true;
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth() ServerAuthenticationState.AttemptAuthenticate() returns result:" + result.ToString()); 
            }
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForAuth", result);

            if (!result && authenticated && m_Extra401Retry) 
            {
                ClearAuthenticatedConnectionResources(); 
                m_Extra401Retry = false; 
                result = true;
            } 

            return result;
        }
 
        /// 
        ///    Determines whether we need to resubmit the request due to the cache settings 
        ///     here it is imperitive that this is not recalled when we already are receiving a cached 
        ///     response
        ///  
        private bool CheckResubmitForCache(ref Exception e) {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmitForCache");

            // Here, we can go into retrying the request 
            if (!CheckCacheRetrieveOnResponse()) {
 
                // NB: We don't have a flag that would control a generic retries 
                // So far we used _AllowAutoRedirect when doing Auth resubmits so the cache intiated retries are put into same bucket
                if (AllowAutoRedirect) { 
                    // Resubmit the request
                    if(Logging.On)Logging.PrintWarning(Logging.Web, this, "", SR.GetString(SR.net_log_cache_validation_failed_resubmit));
                    return true;
                } 

                //fail terribly 
                if(Logging.On)Logging.PrintError(Logging.Web, this, "", SR.GetString(SR.net_log_cache_refused_server_response)); 
                e = new InvalidOperationException(SR.GetString(SR.net_cache_not_accept_response));
                return false; 
            }

            // This may change _HttpResponse memeber based on the CacheProtocol feedback.
            CheckCacheUpdateOnResponse(); 
            return false;
        } 
 
        /// 
        ///    Determines if a HTTP request needs to be 
        ///     resubmitted to a server point, this is called in Response
        ///     Parsing to handle cases such as server Redirects and Authentications
        ///
        ///     true  - if we should reattempt submitting the request 
        ///     false - if the request is complete
        ///  
        private bool CheckResubmit(ref Exception e) { 
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit");
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit"); 

            bool authResubmit = false;

            if (ResponseStatusCode==HttpStatusCode.Unauthorized                 || // 401 
                ResponseStatusCode==HttpStatusCode.ProxyAuthenticationRequired)    // 407
            { 
                try { 
                    //
                    // Check for Authentication 
                    //
                    if (!(authResubmit = CheckResubmitForAuth()))
                    {
                        e = new WebException(SR.GetString(SR.net_servererror, 
                                            NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)),
                                            null, 
                                            WebExceptionStatus.ProtocolError, 
                                            _HttpResponse);
                        GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false"); 
                        return false;
                    }
                }
                catch (System.ComponentModel.Win32Exception w32Exception) { 
                    //
                    // This is a workaround to avoid breaking change since V1 
                    // Basically SSPI may refuse client credential so we abort the request. 
                    // In V1 the error was showing up as WebExceptionStatus.ProtocolError and not with WebExceptionStatus.RequestCanceled
                    // Note that 401 or 407 reported here is from the previous response. 
                    //
                    throw new WebException(
                                            SR.GetString(SR.net_servererror,
                                                NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), 
                                            w32Exception,
                                            WebExceptionStatus.ProtocolError, 
                                            _HttpResponse); 

                } 
            }
            else {
                if (ServerAuthenticationState != null && ServerAuthenticationState.Authorization != null)
                { 
                    HttpWebResponse response = _HttpResponse;
                    if (response != null) 
                    { 
                        response.InternalSetIsMutuallyAuthenticated = ServerAuthenticationState.Authorization.MutuallyAuthenticated;
#if !FEATURE_PAL 
                        if (AuthenticationLevel == AuthenticationLevel.MutualAuthRequired && !response.IsMutuallyAuthenticated)
                        {
                            throw new WebException(SR.GetString(SR.net_webstatus_RequestCanceled),
                                                   new ProtocolViolationException(SR.GetString(SR.net_mutualauthfailed)), 
                                                   WebExceptionStatus.RequestCanceled,
                                                   response); 
                        } 
#endif
                    } 
                }

                // This is a workaround for resubmitting a failed chunked POST throw the proxy that does not support chunked POST
                if (ResponseStatusCode==HttpStatusCode.BadRequest && this.SendChunked && this.ServicePoint.InternalProxyServicePoint) 
                {
                    ClearAuthenticatedConnectionResources(); 
                    return true; 
                }
 

                //
                // Check for Redirection
                // 
                // Table View:
                // Method            301             302             303             307 
                //    *                *               *             GET               * 
                // POST              GET             GET             GET            POST
                // 
                // Put another way:
                //  301 & 302  - All methods are redirected to the same method but POST. POST is redirected to a GET.
                //  303 - All methods are redirected to GET
                //  307 - All methods are redirected to the same method. 
                //
                else if (AllowAutoRedirect && ( 
                    ResponseStatusCode==HttpStatusCode.Ambiguous          || // 300 
                    ResponseStatusCode==HttpStatusCode.Moved              || // 301
                    ResponseStatusCode==HttpStatusCode.Redirect           || // 302 
                    ResponseStatusCode==HttpStatusCode.RedirectMethod     || // 303
                    ResponseStatusCode==HttpStatusCode.RedirectKeepVerb ))   // 307
                {
 
                    _AutoRedirects++;
 
                    if (_AutoRedirects>_MaximumAllowedRedirections) 
                    {
 
                        e = new WebException(SR.GetString(SR.net_tooManyRedirections),
                                             null,
                                             WebExceptionStatus.ProtocolError,
                                             _HttpResponse); 
                        GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
                        return false; 
                    } 

                    string location = _HttpResponse.Headers.Location; 
                    if (location==null)
                    {
                        // Consider: add more detailed message as to why we failed, i.e. no Location header
                        e = new WebException(SR.GetString(SR.net_servererror, 
                                            NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)),
                                            null, 
                                            WebExceptionStatus.ProtocolError, 
                                            _HttpResponse);
                        GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false"); 
                        return false;
                    }
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() Location:" + location);
                    Uri newUri; 
                    try {
                        newUri = new Uri(_Uri, location); 
                    } 
                    catch (UriFormatException exception) {
                        e = new WebException(SR.GetString(SR.net_resubmitprotofailed), exception, WebExceptionStatus.ProtocolError, _HttpResponse); 
                        GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
                        return false;
                    }
                    if (newUri.Scheme != Uri.UriSchemeHttp && newUri.Scheme != Uri.UriSchemeHttps) 
                    {
                        e = new WebException(SR.GetString(SR.net_resubmitprotofailed), null, WebExceptionStatus.ProtocolError, _HttpResponse); 
                        GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false"); 
                        return false;
                    } 
                    try {
                        // Check for permissions against redirect Uri
                        ExecutionContext x = Async ? GetReadingContext().ContextCopy : null;
                        CodeAccessPermission permission = (new WebPermission(NetworkAccess.Connect, newUri)); 
                        if (x == null)
                        { 
                            permission.Demand(); 
                        }
                        else 
                        {
                            ExecutionContext.Run(x, NclUtilities.ContextRelativeDemandCallback, permission);
                        }
                    } 
                    catch (SecurityException exception) {
                        e = new SecurityException(SR.GetString(SR.net_redirect_perm), 
                                                new WebException(SR.GetString(SR.net_resubmitcanceled), exception, WebExceptionStatus.ProtocolError, _HttpResponse)); 

                        GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false"); 
                        return false;
                    }

                    _Uri = newUri; 

                    bool disableUpload = false; 
                    if (ResponseStatusCode>MaxOkStatus) { 
                        if(Logging.On)Logging.PrintWarning(Logging.Web, this, "", SR.GetString(SR.net_log_server_response_error_code, ((int)ResponseStatusCode).ToString(NumberFormatInfo.InvariantInfo)));
                    } 

                    switch (ResponseStatusCode) {
                        case HttpStatusCode.Moved:
                        case HttpStatusCode.Redirect: 
                            if (CurrentMethod.Equals(KnownHttpVerb.Post)) {
                                disableUpload = true; 
                            } 
                            break;
                        case HttpStatusCode.RedirectKeepVerb: 
                            break;
                        default:
                            disableUpload = true;
                            break; 
                    }
 
                    // set new Method 
                    if (disableUpload) {
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() disabling upload HttpWriteMode:" + HttpWriteMode + " SubmitWriteStream#" + ValidationHelper.HashString(_SubmitWriteStream)); 
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() changing Verb from " + CurrentMethod + " to " + KnownHttpVerb.Get);
                        CurrentMethod = KnownHttpVerb.Get;
                        ExpectContinue = false;
                        HttpWriteMode = HttpWriteMode.None; 
                    }
 
                    // 
                    // Do _not_ automatically reuse the credential object on a redirection unless
                    // it is specifically a CredentialCache or SystemNetworkCredential object. 
                    //
                    // The CredentialCache object stores credentials for specific URIs and
                    // authentication schemes.  Therefore the application has given explicit
                    // permission to use/send those credentials to a specific site using a 
                    // specific authentication scheme.
                    // 
                    // A SystemNetworkCredential object represents current default credentials. 
                    // It is deemed safe to reuse them on an automatic redirection since the
                    // authentication SSP are trusted to only use safe authentication schemes 
                    // for default credentials.

#if !FEATURE_PAL
                    // Is current credential object a CredentialCache type? 
                    ICredentials authTemp = Credentials as CredentialCache;
                    if (authTemp == null) { 
                        // not CredentialCache - is it a SystemNetworkCredential type? 
                        authTemp = Credentials as SystemNetworkCredential;
                    } 
                    if (authTemp == null) {
                        // object is not either type that is safe for redirection - remove it
                        Credentials = null;
                    } 
#else
                    Credentials = null; 
#endif // !FEATURE_PAL 

                    // 
                    // do the necessary cleanup on the Headers involved in the
                    // Authentication handshake.
                    //
                    ProxyAuthenticationState.ClearAuthReq(this); 
                    ServerAuthenticationState.ClearAuthReq(this);
 
                    //strip referer if coming from an https site 
                    if(_OriginUri.Scheme == Uri.UriSchemeHttps) {
                        _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Referer); 
                    }

                    // resubmit
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit() CurrentMethod=" + CurrentMethod); 
                }
                else if (ResponseStatusCode > MaxRedirectionStatus)          // > 399 = fatal 
                { 
                    e = new WebException(SR.GetString(SR.net_servererror,
                                        NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)), 
                                        null,
                                        WebExceptionStatus.ProtocolError,
                                        _HttpResponse);
                    GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false"); 
                    return false;
                } 
                else if (AllowAutoRedirect && ResponseStatusCode > MaxOkStatus) //some of 3XX and AllowAutoRedirect==true will result into an exceptional respone 
                {
                    e = new WebException(SR.GetString(SR.net_servererror, 
                                        NetRes.GetWebStatusCodeString(ResponseStatusCode, _HttpResponse.StatusDescription)),
                                        null,
                                        WebExceptionStatus.ProtocolError,
                                        _HttpResponse); 
                    GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
                    return false; 
                } 
                else // SUCCESS Status is <= 299 or (<=399 && AllowAutoRedirect==false) will result into a normal (non exceptional) response
                { 
                    GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
                    return false;
                }
            } 

            GlobalLog.Assert(HttpWriteMode != HttpWriteMode.Unknown, "HttpWebRequest#{0}::CheckResubmit()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode); 
            if (HttpWriteMode!=HttpWriteMode.None && !AllowWriteStreamBuffering && (HttpWriteMode!=HttpWriteMode.ContentLength || ContentLength!=0)) 
            {
                e = new WebException(SR.GetString(SR.net_need_writebuffering), null, WebExceptionStatus.ProtocolError, _HttpResponse); 
                GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "false");
                return false;
            }
 
            if (!authResubmit){
                ClearAuthenticatedConnectionResources(); 
            } 

            if(Logging.On)Logging.PrintWarning(Logging.Web, this, "", SR.GetString(SR.net_log_resubmitting_request)); 
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckResubmit", "true");
            return true;
        }
 
        /*++
 
        Routine Description: 

            ClearRequestForResubmit - prepares object for resubmission and recall 
                of submit request, for redirects, authentication, and other uses
                This is needed to prevent duplicate headers being added, and other
                such things.
 
        Arguments:
 
            None. 

        Return Value: 

            None.

        --*/ 
        private void ClearRequestForResubmit() {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit"); 
 
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Host);
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Connection); 
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ProxyConnection);
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ContentLength);
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.TransferEncoding);
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Expect); 

            if (_HttpResponse != null && _HttpResponse.ResponseStream != null) { 
                // 
                // We just drain the response data, and throw them away since we're redirecting or authenticating.
                // 
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() draining ResponseStream");
                if (!_HttpResponse.KeepAlive) {
                    ConnectStream liveStream = _HttpResponse.ResponseStream as ConnectStream;
                    if (liveStream != null ) { 
                        // The response stream may be closed at any time by the server.
                        // At this point we don't want to drain such a ConnectStream. 
                        liveStream.ErrorResponseNotify(false); 
                    }
                } 
                ICloseEx icloseEx = _HttpResponse.ResponseStream as ICloseEx;
                if (icloseEx != null) {
                    icloseEx.CloseEx(CloseExState.Silent);
                } 
                else {
                    _HttpResponse.ResponseStream.Close(); 
                } 
            }
 
            _AbortDelegate = null;

            if (_SubmitWriteStream != null) {
                // 
                // We're uploading and need to resubmit for Authentication or Redirect.
                // if the response wants to keep alive the connection we shouldn't be closing 
                // it (this would also brake connection-oriented authentication schemes such as NTLM). 
                // so we need to flush all the data to the wire.
                // if the server is closing the connection, instead, we can just close our side as well. 
                if ((_HttpResponse != null && _HttpResponse.KeepAlive) || _SubmitWriteStream.IgnoreSocketErrors)
                {
                    //
                    // the server wants to keep the connection alive. 
                    // if we're uploading data, we need to make sure that we upload all
                    // of it before we start resubmitting. 
                    // give the stream to the user if he didn't get it yet. 
                    // if the user has set ContentLength to a big number, then we might be able
                    // to just decide to close the connection, but we need to be careful to NTLM. 
                    //
                    GlobalLog.Assert(HttpWriteMode != HttpWriteMode.Unknown, "HttpWebRequest#{0}::ClearRequestForResubmit()|HttpWriteMode:{1}", ValidationHelper.HashString(this), HttpWriteMode);
                    if (HasEntityBody)
                    { 
                        //
                        // we're uploading 
                        // 
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() _WriteAResult:" + ValidationHelper.ToString(_WriteAResult));
 
                        //
                        // the user didn't get the stream yet, give it to him
                        //
                        GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() calling SetRequestContinue()"); 
                        SetRequestContinue();
 
                        // We should only close the stream if we're not giving it back to the app. 
                        if (!Async && UserRetrievedWriteStream)
                            _SubmitWriteStream.CallDone(); 
                    }
                }

                if ((Async || UserRetrievedWriteStream) && _OldSubmitWriteStream != null && _OldSubmitWriteStream != _SubmitWriteStream) { 
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::ClearRequestForResubmit() closing RequestStream");
                    _SubmitWriteStream.CloseInternal(true); 
                } 
            }
 
            m_ContinueGate.Reset();
            _RerequestCount += 1;

            m_BodyStarted = false; 
            HeadersCompleted = false;
            _WriteBuffer  = null; 
            m_Extra401Retry = false; 

#if TRAVE 
            _OldResponse = _HttpResponse;
#endif
            _HttpResponse = null;
 
            if (!Aborted && Async)
                _CoreResponse = null; 
        } 

        // 
        //  Oprionally:
        //  1) copies off the response stream
        //  2) closes SubmitStream
        //  3) updates ServicePoint 100-Continue expectation for future requests 
        //
        //  Should never throw 
        // 
        private void FinishRequest(HttpWebResponse response, Exception errorException)
        { 

            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::FinishRequest()");

            if (!_ReadAResult.InternalPeekCompleted && m_Aborted != AbortState.Public) // otherwise it's too late 
            {
                if (response != null && errorException != null) 
                { 
                    // if this is a protocol exception copy off stream, don't just close it
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckFinalStatus() - status" + (int)ResponseStatusCode); 
                    response.ResponseStream = MakeMemoryStream(response.ResponseStream); // Never throws
                }
            }
 
            if (errorException != null && _SubmitWriteStream != null && !_SubmitWriteStream.IsClosed)
            { 
                _SubmitWriteStream.ErrorResponseNotify(false); 
            }
 
            //
            // turn off expectation of 100 continue (we'll keep sending an
            // "Expect: 100-continue" header to a 1.1 server though)
            // 
            if ( errorException == null && _HttpResponse != null &&
                 ( _HttpWriteMode == HttpWriteMode.Chunked || _ContentLength > 0 ) && 
                 ExpectContinue && !Saw100Continue  && 
                 _ServicePoint.Understands100Continue &&
                 !IsTunnelRequest && 
                 ResponseStatusCode <= MaxOkStatus)
            {
                _ServicePoint.Understands100Continue = false;
            } 
        }
 
        // 
        // Never throws
        // 
        private Stream MakeMemoryStream(Stream stream) {
           // GlobalLog.ThreadContract(ThreadKinds.Sync, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::MakeMemoryStream");

            if (stream == null || stream is SyncMemoryStream) 
                return stream;
 
            SyncMemoryStream memoryStream = new SyncMemoryStream(0);      // buffered Stream to save off data 
            try {
                // 
                // Now drain the Stream
                //
                if (stream.CanRead) {
                    byte [] buffer = new byte[1024]; 
                    int bytesTransferred = 0;
 
                    // 

 

                    int maxBytesToBuffer = (HttpWebRequest.DefaultMaximumErrorResponseLength == -1)?buffer.Length:HttpWebRequest.DefaultMaximumErrorResponseLength*1024;
                    while ((bytesTransferred = stream.Read(buffer, 0, Math.Min(buffer.Length, maxBytesToBuffer))) > 0)
                    { 
                        memoryStream.Write(buffer, 0, bytesTransferred);
                        if(HttpWebRequest.DefaultMaximumErrorResponseLength != -1) 
                            maxBytesToBuffer -= bytesTransferred; 
                    }
                } 
                memoryStream.Position = 0;
            }
            catch {
            } 
            finally
            { 
                try { 
                    ICloseEx icloseEx = stream as ICloseEx;
                    if (icloseEx != null) { 
                        icloseEx.CloseEx(CloseExState.Silent);
                    }
                    else {
                        stream.Close(); 
                    }
                } 
                catch { 
                }
            } 
            return memoryStream;
        }

        ///  
        ///    
        ///       Adds a range header to the request for a specified range. 
        ///     
        /// 
        public void AddRange(int from, int to) { 
            AddRange("bytes", from, to);
        }

 
        /// 
        ///     
        ///       Adds a range header to a request for a specific 
        ///       range from the beginning or end
        ///       of the requested data. 
        ///       To add the range from the end pass negative value
        ///       To add the range from the some offset to the end pass positive value
        ///    
        ///  
        public void AddRange(int range) {
            AddRange("bytes", range); 
        } 

        public void AddRange(string rangeSpecifier, int from, int to) { 

            //
            // Do some range checking before assembling the header
            // 

            if (rangeSpecifier == null) { 
                throw new ArgumentNullException("rangeSpecifier"); 
            }
            if ((from < 0) || (to < 0)) { 
                throw new ArgumentOutOfRangeException(SR.GetString(SR.net_rangetoosmall));
            }
            if (from > to) {
                throw new ArgumentOutOfRangeException(SR.GetString(SR.net_fromto)); 
            }
            if (!WebHeaderCollection.IsValidToken(rangeSpecifier)) { 
                throw new ArgumentException(SR.GetString(SR.net_nottoken), "rangeSpecifier"); 
            }
            if (!AddRange(rangeSpecifier, from.ToString(NumberFormatInfo.InvariantInfo), to.ToString(NumberFormatInfo.InvariantInfo))) { 
                throw new InvalidOperationException(SR.GetString(SR.net_rangetype));
            }
        }
 
        public void AddRange(string rangeSpecifier, int range) {
            if (rangeSpecifier == null) { 
                throw new ArgumentNullException("rangeSpecifier"); 
            }
            if (!WebHeaderCollection.IsValidToken(rangeSpecifier)) { 
                throw new ArgumentException(SR.GetString(SR.net_nottoken), "rangeSpecifier");
            }
            if (!AddRange(rangeSpecifier, range.ToString(NumberFormatInfo.InvariantInfo), (range >= 0) ? "" : null)) {
                throw new InvalidOperationException(SR.GetString(SR.net_rangetype)); 
            }
        } 
 
        //
        // bool AddRange(rangeSpecifier, from, to) 
        //
        //  Add or extend a range header. Various range types can be specified
        //  via rangeSpecifier, but only one type of Range request will be made
        //  e.g. a byte-range request, or a row-range request. Range types 
        //  cannot be mixed
        // 
        private bool AddRange(string rangeSpecifier, string from, string to) { 

            string curRange = _HttpRequestHeaders[HttpKnownHeaderNames.Range]; 

            if ((curRange == null) || (curRange.Length == 0)) {
                curRange = rangeSpecifier + "=";
            } 
            else {
                if (String.Compare(curRange.Substring(0, curRange.IndexOf('=')), rangeSpecifier, StringComparison.OrdinalIgnoreCase) != 0) { 
                    return false; 
                }
                curRange = string.Empty; 
            }
            curRange += from.ToString();
            if (to != null) {
                curRange += "-" + to; 
            }
            _HttpRequestHeaders.SetAddVerified(HttpKnownHeaderNames.Range, curRange); 
            return true; 
        }
 
        private static string UniqueGroupId {
            get {
                return (Interlocked.Increment(ref s_UniqueGroupId)).ToString(NumberFormatInfo.InvariantInfo);
            } 
        }
 
#if HTTP_HEADER_EXTENSIONS_SUPPORTED 

        ///  
        ///    Assembles and creates a new extension header, and
        ///     returns an extension object that can be used to
        ///      add extension headers
        ///  
        public HttpExtension CreateExtension(string uri, string header) {
            int id = _NextExtension; 
            HttpExtension extension = new HttpExtension(id, uri, header); 

            _NextExtension++; 

            return extension;
        }
 

 
        ///  
        ///    Assembles and creates a new extension header, by adding it the extension object 
        ///  
        public void AddExtension(HttpExtension extension, string header, string value) {
            StringBuilder sb = new StringBuilder(100);

            if (extension == null) { 
                throw new ArgumentNullException("extension");
            } 
 
            if (! extension.HasAddedExtensionHeader) {
                StringBuilder sb2 = new StringBuilder(100); 

                extension.HasAddedExtensionHeader = true;
                sb2.Append(extension.Header);
                sb2.Append(": \""); 
                sb2.Append(extension.Uri);
                sb2.Append("\"; ns="); 
                sb2.Append(extension.ID); 

                _HttpRequestHeaders.Add(sb2.ToString()); 
            }

            sb.Append(extension.ID);
            sb.Append('-'); 
            sb.Append(header);
 
            _HttpRequestHeaders.Add(sb.ToString(), value); 
        }
#endif // HTTP_HEADER_EXTENSIONS_SUPPORTED 

    }
}


                        

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