FtpWebRequest.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / FtpWebRequest.cs / 1305376 / FtpWebRequest.cs

                            // ------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ----------------------------------------------------------------------------- 
//
 
namespace System.Net { 
    using System.Collections;
    using System.IO; 
    using System.Text;
    using System.Net.Sockets;
    using System.Net.Cache;
    using System.Threading; 
    using System.Security;
    using System.Security.Cryptography.X509Certificates ; 
    using System.Security.Permissions; 
    using System.Security.Authentication;
    using System.Globalization; 


    /// 
    /// Allows us to control what the request is used for (based on the type of behavior, 
    ///     that the command calls for)
    ///  
    internal enum FtpOperation { 
        DownloadFile          = 0,
        ListDirectory         = 1, 
        ListDirectoryDetails  = 2,
        UploadFile            = 3,
        UploadFileUnique      = 4,
        AppendFile            = 5, 
        DeleteFile            = 6,
        GetDateTimestamp      = 7, 
        GetFileSize           = 8, 
        Rename                = 9,
        MakeDirectory         = 10, 
        RemoveDirectory       = 11,
        PrintWorkingDirectory = 12,
        Other                 = 13,
    } 

    [Flags] 
    internal enum FtpMethodFlags { 
        None                      = 0x0,
        IsDownload                = 0x1, 
        IsUpload                  = 0x2,
        TakesParameter            = 0x4,
        MayTakeParameter          = 0x8,
        DoesNotTakeParameter      = 0x10, 
        ParameterIsDirectory      = 0x20,
        ShouldParseForResponseUri = 0x40, 
        HasHttpCommand            = 0x80, 
        MustChangeWorkingDirectoryToPath  = 0x100
    } 

    internal class FtpMethodInfo {
        internal string          Method;
        internal FtpOperation    Operation; 
        internal FtpMethodFlags  Flags;
        internal string          HttpCommand; 
 
        internal FtpMethodInfo(string         method,
                               FtpOperation   operation, 
                               FtpMethodFlags flags,
                               string         httpCommand)
        {
            Method      = method; 
            Operation   = operation;
            Flags       = flags; 
            HttpCommand = httpCommand; 
        }
 
        internal bool HasFlag(FtpMethodFlags flags) {
            return (Flags & flags) != 0;
        }
 
        internal bool IsCommandOnly {
            get { return (Flags & (FtpMethodFlags.IsDownload | FtpMethodFlags.IsUpload)) == 0; } 
        } 

        internal bool IsUpload { 
            get { return (Flags & FtpMethodFlags.IsUpload) != 0; }
        }

        internal bool IsDownload { 
            get { return (Flags & FtpMethodFlags.IsDownload) != 0; }
        } 
 
        internal bool HasHttpCommand {
            get { return (Flags & FtpMethodFlags.HasHttpCommand) != 0; } 
        }

        /// 
        ///    True if we should attempt to get a response uri 
        ///    out of a server response
        ///  
        internal bool ShouldParseForResponseUri { 
            get { return (Flags & FtpMethodFlags.ShouldParseForResponseUri) != 0; }
        } 

        internal static FtpMethodInfo GetMethodInfo(string method)  {
            method = method.ToUpper(CultureInfo.InvariantCulture);
            foreach (FtpMethodInfo methodInfo in KnownMethodInfo) 
                if (method == methodInfo.Method)
                    return methodInfo; 
            // We don't support generic methods 
            throw new ArgumentException(SR.GetString(SR.net_ftp_unsupported_method), "method");
        } 

        static readonly FtpMethodInfo[] KnownMethodInfo =
        {
            new FtpMethodInfo(WebRequestMethods.Ftp.DownloadFile, 
                              FtpOperation.DownloadFile,
                              FtpMethodFlags.IsDownload 
                              | FtpMethodFlags.HasHttpCommand 
                              | FtpMethodFlags.TakesParameter,
                              "GET"), 
            new FtpMethodInfo(WebRequestMethods.Ftp.ListDirectory,
                              FtpOperation.ListDirectory,
                              FtpMethodFlags.IsDownload
                              | FtpMethodFlags.MustChangeWorkingDirectoryToPath 
                              | FtpMethodFlags.HasHttpCommand
                              | FtpMethodFlags.MayTakeParameter, 
                              "GET"), 
            new FtpMethodInfo(WebRequestMethods.Ftp.ListDirectoryDetails,
                              FtpOperation.ListDirectoryDetails, 
                              FtpMethodFlags.IsDownload
                              | FtpMethodFlags.MustChangeWorkingDirectoryToPath
                              | FtpMethodFlags.HasHttpCommand
                              | FtpMethodFlags.MayTakeParameter, 
                              "GET"),
            new FtpMethodInfo(WebRequestMethods.Ftp.UploadFile, 
                              FtpOperation.UploadFile, 
                              FtpMethodFlags.IsUpload
                              | FtpMethodFlags.TakesParameter, 
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.UploadFileWithUniqueName,
                              FtpOperation.UploadFileUnique,
                              FtpMethodFlags.IsUpload 
                              | FtpMethodFlags.MustChangeWorkingDirectoryToPath
                              | FtpMethodFlags.DoesNotTakeParameter 
                              | FtpMethodFlags.ShouldParseForResponseUri, 
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.AppendFile, 
                              FtpOperation.AppendFile,
                              FtpMethodFlags.IsUpload
                              | FtpMethodFlags.TakesParameter,
                              null), 
            new FtpMethodInfo(WebRequestMethods.Ftp.DeleteFile,
                              FtpOperation.DeleteFile, 
                              FtpMethodFlags.TakesParameter, 
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.GetDateTimestamp, 
                              FtpOperation.GetDateTimestamp,
                              FtpMethodFlags.TakesParameter,
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.GetFileSize, 
                              FtpOperation.GetFileSize,
                              FtpMethodFlags.TakesParameter, 
                              null), 
            new FtpMethodInfo(WebRequestMethods.Ftp.Rename,
                              FtpOperation.Rename, 
                              FtpMethodFlags.TakesParameter,
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.MakeDirectory,
                              FtpOperation.MakeDirectory, 
                              FtpMethodFlags.TakesParameter
                              | FtpMethodFlags.ParameterIsDirectory, 
                              null), 
            new FtpMethodInfo(WebRequestMethods.Ftp.RemoveDirectory,
                              FtpOperation.RemoveDirectory, 
                              FtpMethodFlags.TakesParameter
                              | FtpMethodFlags.ParameterIsDirectory,
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.PrintWorkingDirectory, 
                              FtpOperation.PrintWorkingDirectory,
                              FtpMethodFlags.DoesNotTakeParameter, 
                              null) 
        };
 
    }

    /// 
    /// The FtpWebRequest class implements a basic FTP client 
    /// interface.
    ///  
    public sealed class FtpWebRequest : WebRequest { 
        private object          m_SyncObject;
        private ICredentials    m_AuthInfo; 
        private readonly Uri    m_Uri;
        private FtpMethodInfo   m_MethodInfo;
        private string          m_RenameTo = null;
        private bool            m_GetRequestStreamStarted; 
        private bool            m_GetResponseStarted;
        private DateTime        m_StartTime; 
        private int             m_Timeout = s_DefaultTimeout; 
        private int             m_RemainingTimeout;
        private long            m_ContentLength = 0; 
        private long            m_ContentOffset = 0;
        private IWebProxy       m_Proxy;
#if !FEATURE_PAL
        private X509CertificateCollection m_ClientCertificates; 
#endif // !FEATURE_PAL
        private bool            m_KeepAlive = true; 
        private bool            m_Passive = true; 
        private bool            m_Binary = true;
        private string          m_ConnectionGroupName; 
        private ServicePoint    m_ServicePoint;

        private bool            m_CacheDone; // Not sure why but the command stream wants to notify the request on every pipiline closure closure by invoking RequestCallback.
                                             // m_CacheDone is to facilitate PutConnection decision and to prevent bothering cache protocol when it's all completed. 

        private bool            m_Async; 
        private bool            m_Aborted; 
        private bool            m_TimedOut;
 
        private HttpWebRequest  m_HttpWebRequest;
        private Exception       m_Exception;

        private TimerThread.Queue    m_TimerQueue = s_DefaultTimerQueue; 
        private TimerThread.Callback m_TimerCallback;
 
        private bool                 m_EnableSsl; 
        private bool                 m_ProxyUserSet;
        private ConnectionPool       m_ConnectionPool; 
        private FtpControlStream     m_Connection;
        private Stream               m_Stream;
        private RequestStage         m_RequestStage;
        private bool                 m_OnceFailed; 
        private WebHeaderCollection  m_FtpRequestHeaders;
        private FtpWebResponse       m_FtpWebResponse; 
        private int                  m_ReadWriteTimeout = 5*60*1000;  //5 minutes. 

 
        private ContextAwareResult  m_WriteAsyncResult;
        private LazyAsyncResult     m_ReadAsyncResult;
        private LazyAsyncResult     m_RequestCompleteAsyncResult;
 
        private static readonly GeneralAsyncDelegate m_AsyncCallback = new GeneralAsyncDelegate(AsyncCallbackWrapper);
        private static readonly CreateConnectionDelegate m_CreateConnectionCallback = new CreateConnectionDelegate(CreateFtpConnection); 
        private static readonly NetworkCredential DefaultFtpNetworkCredential = new NetworkCredential("anonymous", "anonymous@", String.Empty); 
        private static readonly int s_DefaultTimeout = WebRequest.DefaultTimeout;
        private static readonly TimerThread.Queue s_DefaultTimerQueue = TimerThread.GetOrCreateQueue(s_DefaultTimeout); 

        // Used by FtpControlStream
        internal FtpMethodInfo MethodInfo {
            get { 
                return m_MethodInfo;
            } 
        } 

        // Used by FtpControlStream 
        internal static NetworkCredential DefaultNetworkCredential{
            get {
                return DefaultFtpNetworkCredential;
            } 
        }
 
        // 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 {
                RequestCachePolicy policy = RequestCacheManager.GetBinding(Uri.UriSchemeFtp).Policy;
                if (policy == null) 
                    return WebRequest.DefaultCachePolicy;
                return policy; 
            } 
            set {
                // 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.UriSchemeFtp);
                RequestCacheManager.SetBinding(Uri.UriSchemeFtp, new RequestCacheBinding(binding.Cache, binding.Validator, value)); 
            }
        } 
 
        /// 
        ///  
        /// Selects upload or download of files. WebRequestMethods.Ftp.DownloadFile is default.
        /// Not allowed to be changed once request is started.
        /// 
        ///  
        public override string Method {
            get { 
                return m_MethodInfo.Method; 
            }
            set { 
                if (String.IsNullOrEmpty(value)) {
                    throw new ArgumentException(SR.GetString(SR.net_ftp_invalid_method_name), "value");
                }
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                try { 
                    m_MethodInfo = FtpMethodInfo.GetMethodInfo(value);
                } catch (ArgumentException) { 
                    throw new ArgumentException(SR.GetString(SR.net_ftp_unsupported_method), "value");
                }
           }
        } 

        ///  
        ///  
        /// Sets the target name for the WebRequestMethods.Ftp.Rename command
        /// Not allowed to be changed once request is started. 
        /// 
        /// 
        public string RenameTo {
            get { 
                return m_RenameTo;
            } 
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }

                if (String.IsNullOrEmpty(value)) {
                    throw new ArgumentException(SR.GetString(SR.net_ftp_invalid_renameto), "value"); 
                }
 
                m_RenameTo = value; 
           }
        } 

        /// 
        /// Used for clear text authentication with FTP server
        ///  
        public override ICredentials Credentials {
            get { 
                return m_AuthInfo; 
            }
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                }
                if (value == null) { 
                    throw new ArgumentNullException("value");
                } 
                if (value is SystemNetworkCredential) { 
                    throw new ArgumentException(SR.GetString(SR.net_ftp_no_defaultcreds), "value");
                } 
                m_AuthInfo = value;
            }
        }
 
        /// 
        /// Gets the Uri used to make the request 
        ///  
        public override Uri RequestUri {
            get { 
                return m_Uri;
            }
        }
 
        /// 
        /// Timeout of the blocking calls such as GetResponse and GetRequestStream (default 100 secs) 
        ///  
        public override int Timeout {
            get { 
                return m_Timeout;
            }
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                if (value<0 && value!=System.Threading.Timeout.Infinite) { 
                    throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_ge_zero));
                } 
                if (m_Timeout != value)
                {
                    m_Timeout = value;
                    m_TimerQueue = null; 
                }
            } 
        } 

        // This can always be calculaed as Remaining = Timeout - (Now - Start) 
        // but we are keeping this for performance reasons (To avoid unnecessary
        // calculations). This can be removed if the performance gains are
        // considered negligible and not necessary
        internal int RemainingTimeout { 
            get {
                return m_RemainingTimeout; 
            } 
        }
 


        /// 
        ///    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 m_ReadWriteTimeout;
            }
            set { 
                if (m_GetResponseStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                if (value<=0 && value!=System.Threading.Timeout.Infinite) {
                    throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_gt_zero)); 
                }
                m_ReadWriteTimeout = value;
            }
        } 

        ///  
        /// Used to specify what offset we will read at 
        /// 
        public long ContentOffset { 
            get {
                return m_ContentOffset;
            }
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                if (value<0) {
                    throw new ArgumentOutOfRangeException("value"); 
                }
                m_ContentOffset = value;
            }
        } 

 
 
        /// 
        /// Gets or sets the data size of to-be uploaded data 
        /// 
        public override long ContentLength {
            get {
                return m_ContentLength; 
            }
            set { 
                m_ContentLength = value; 
            }
        } 

        /// 
        /// Uses an HTTP proxy if needed to send FTP request
        ///  
        public override IWebProxy Proxy {
            get { 
                ExceptionHelper.WebPermissionUnrestricted.Demand(); 
                return m_Proxy;
            } 
            set {
                ExceptionHelper.WebPermissionUnrestricted.Demand();
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }
                m_ProxyUserSet = true; 
                m_Proxy = value; 
                m_ServicePoint = null;
                ServicePoint refreshIt = ServicePoint ; 
            }
        }

        ///  
        /// Allows private ConnectionPool(s) to be used
        ///  
        public override string ConnectionGroupName { 
            get {
                return m_ConnectionGroupName; 
            }
            set {
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }
                m_ConnectionGroupName = value; 
            } 
        }
 
        /// 
        /// Generates a service point for this request, and allows setting of Connection settings
        /// 
        public ServicePoint ServicePoint { 
            get {
                if (m_ServicePoint == null) 
                { 
                    IWebProxy proxy = m_Proxy;
                    if (!m_ProxyUserSet) 
                        proxy = WebRequest.InternalDefaultWebProxy;

                    ServicePoint servicePoint = ServicePointManager.FindServicePoint(m_Uri, proxy);
 
                    lock (m_SyncObject) {
                        if (m_ServicePoint == null) 
                        { 
                            m_ServicePoint = servicePoint;
                            m_Proxy = proxy; 
                        }
                    }
                }
                return m_ServicePoint; 
            }
        } 
 
        internal bool Aborted {
            get { 
                return m_Aborted;
            }
        }
 
        /// 
        ///  
        /// Initializes a new instance of the  
        /// class.
        ///  
        /// 
        internal FtpWebRequest(Uri uri) {
           (new WebPermission(NetworkAccess.Connect, uri)).Demand();
 
           if (Logging.On) Logging.PrintInfo(Logging.Web, this, ".ctor", uri.ToString());
 
           if ((object)uri.Scheme != (object)Uri.UriSchemeFtp) 
               throw new ArgumentOutOfRangeException("uri");
 
            m_TimerCallback = new TimerThread.Callback(TimerCallback);
            m_SyncObject = new object();

            NetworkCredential networkCredential = null; 
            m_Uri = uri;
            m_MethodInfo = FtpMethodInfo.GetMethodInfo(WebRequestMethods.Ftp.DownloadFile); 
            if (m_Uri.UserInfo != null && m_Uri.UserInfo.Length != 0) { 
                string userInfo = m_Uri.UserInfo;
                string username = userInfo; 
                string password = "";
                int index = userInfo.IndexOf(':');
                if (index != -1) {
                    username = Uri.UnescapeDataString(userInfo.Substring(0, index)); 
                    index++; // skip ':'
                    password = Uri.UnescapeDataString(userInfo.Substring(index, userInfo.Length - index)); 
                } 
                networkCredential = new NetworkCredential(username, password);
            } 
            if (networkCredential == null) {
                networkCredential = DefaultFtpNetworkCredential;
            }
            m_AuthInfo = networkCredential; 
            SetupCacheProtocol(m_Uri);
        } 
 

        // 
        // Used to query for the Response of an FTP request
        //
        public override WebResponse GetResponse()
        { 
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetResponse", "");
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "GetResponse", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse"); 

            try { 
                CheckError();

                if (m_FtpWebResponse != null)
                    return m_FtpWebResponse; 

                if (m_GetResponseStarted) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall)); 
                }
 
                m_GetResponseStarted = true;

                m_StartTime = DateTime.UtcNow;
                m_RemainingTimeout = Timeout; 

                // We don't really need this variable, but we just need 
                // to call the property to measure its execution time 
                ServicePoint servicePoint = ServicePoint;
 
                if (Timeout != System.Threading.Timeout.Infinite)
                {
                    m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
 
                    if(m_RemainingTimeout <= 0){
                        throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout); 
                    } 
                }
 
                if (ServicePoint.InternalProxyServicePoint)
                {
                    if (EnableSsl) {
                        m_GetResponseStarted = false; 
                        throw new WebException(SR.GetString(SR.net_ftp_proxy_does_not_support_ssl));
                    } 
 
                    try {
                        HttpWebRequest httpWebRequest = GetHttpWebRequest(); 
                        if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest);

                        m_FtpWebResponse = new FtpWebResponse((HttpWebResponse)httpWebRequest.GetResponse());
                    } catch (WebException webException) { 
                        if (webException.Response != null &&
                            webException.Response is HttpWebResponse) 
                        { 
                            webException = new WebException(webException.Message,
                                null, 
                                webException.Status,
                                new FtpWebResponse((HttpWebResponse)webException.Response),
                                webException.InternalStatus);
                        } 
                        SetException(webException);
                        throw webException; 
                    } 
                    // Catch added to address Bug # 545645
                    catch (InvalidOperationException invalidOpException) 
                    {
                        SetException(invalidOpException);
                        FinishRequestStage(RequestStage.CheckForError);
                        throw; 
                    }
                } 
                else 
                {
                    RequestStage prev = FinishRequestStage(RequestStage.RequestStarted); 
                    if (prev >= RequestStage.RequestStarted)
                    {
                        if (prev < RequestStage.ReadReady)
                        { 
                            lock (m_SyncObject)
                            { 
                                if (m_RequestStage < RequestStage.ReadReady) 
                                    m_ReadAsyncResult = new LazyAsyncResult(null, null, null);
                            } 

                            // GetRequeststream or BeginGetRequestStream has not finished yet?
                            if (m_ReadAsyncResult != null)
                                m_ReadAsyncResult.InternalWaitForCompletion(); 

                            CheckError(); 
                        } 
                    }
                    else 
                    {
                        do
                        {
                            SubmitRequest(false); 
                            if (m_MethodInfo.IsUpload)
                                FinishRequestStage(RequestStage.WriteReady); 
                            else 
                                FinishRequestStage(RequestStage.ReadReady);
                            CheckError(); 
                        } while (!CheckCacheRetrieveOnResponse());

                        EnsureFtpWebResponse(null);
                        // This may update the Stream memeber on m_FtpWebResponse based on the CacheProtocol feedback. 
                        CheckCacheUpdateOnResponse();
 
                        if (m_FtpWebResponse.IsFromCache) 
                            FinishRequestStage(RequestStage.ReleaseConnection);
                    } 
                }
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "GetResponse", exception);
 
                // if m_Exception == null, we are about to throw an exception to the user
                // and we haven't saved the exception, which also means we haven't dealt 
                // with it. So just release the connection and log this for investigation 
                if (m_Exception == null) {
                    if(Logging.On)Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_unexpected_exception, "GetResponse()")); 

                    if (!NclUtilities.IsFatal(exception)){
                        GlobalLog.Assert("Find out why we are getting an unexpected exception.");
                    } 
                    SetException(exception);
                    FinishRequestStage(RequestStage.CheckForError); 
                } 
                throw;
            } finally { 

                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse", "returns #"+ValidationHelper.HashString(m_FtpWebResponse));
                if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponse", "");
            } 
            return m_FtpWebResponse;
        } 
 
        /// 
        ///  
        /// Used to query for the Response of an FTP request [async version]
        /// 
        [HostProtection(ExternalThreading=true)]
        public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) 
        {
            if(Logging.On)Logging.Enter(Logging.Web, this, "BeginGetResponse", ""); 
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "BeginGetResponse", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse");
 
            ContextAwareResult asyncResult;

            try {
                if (m_FtpWebResponse != null) 
                {
                    asyncResult = new ContextAwareResult(this, state, callback); 
                    asyncResult.InvokeCallback(m_FtpWebResponse); 
                    return asyncResult;
                } 

                if (m_GetResponseStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                } 

                m_GetResponseStarted = true; 
                CheckError(); 

                if (ServicePoint.InternalProxyServicePoint) 
                {
                    HttpWebRequest httpWebRequest = GetHttpWebRequest();
                    if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest);
                    asyncResult = (ContextAwareResult)httpWebRequest.BeginGetResponse(callback, state); 
                }
                else 
                { 
                    RequestStage prev = FinishRequestStage(RequestStage.RequestStarted);
                    asyncResult = new ContextAwareResult(true, true, this, state, callback); 
                    m_ReadAsyncResult = asyncResult;

                    if (prev >= RequestStage.RequestStarted)
                    { 
                        // To make sure the context is flowed
                        asyncResult.StartPostingAsyncOp(); 
                        asyncResult.FinishPostingAsyncOp(); 

                        if (prev >= RequestStage.ReadReady) 
                            asyncResult = null;
                        else
                        {
                            lock (m_SyncObject) 
                            {
                                if (m_RequestStage >= RequestStage.ReadReady) 
                                    asyncResult = null;; 
                            }
                        } 

                        if(asyncResult == null)
                        {
                            // need to complete it now 
                            asyncResult = (ContextAwareResult)m_ReadAsyncResult;
                            if (!asyncResult.InternalPeekCompleted) 
                                asyncResult.InvokeCallback(); 
                        }
                    } 
                    else
                    {
                        // Do internal processing in this handler to optimize context flowing.
                        lock (asyncResult.StartPostingAsyncOp()) 
                        {
                            SubmitRequest(true); 
                            asyncResult.FinishPostingAsyncOp(); 
                        }
                        FinishRequestStage(RequestStage.CheckForError); 
                    }
                }
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetResponse", exception); 
                throw;
            } finally { 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse"); 
                if(Logging.On)Logging.Exit(Logging.Web, this, "BeginGetResponse", "");
            } 
            return asyncResult;
        }

        ///  
        /// Returns result of query for the Response of an FTP request [async version]
        ///  
        public override WebResponse EndGetResponse(IAsyncResult asyncResult) { 

            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetResponse", ""); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse");

            try {
                // parameter validation 
                if (asyncResult==null) {
                    throw new ArgumentNullException("asyncResult"); 
                } 
                LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
                if (castedAsyncResult==null) { 
                    throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
                }
                if (HttpProxyMode?(castedAsyncResult.AsyncObject!=this.GetHttpWebRequest()):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")); 
                }
 
                if (HttpProxyMode) {
                    try {
                        CheckError();
                        if (m_FtpWebResponse == null) 
                        {
                            m_FtpWebResponse = new FtpWebResponse((HttpWebResponse)GetHttpWebRequest().EndGetResponse(asyncResult)); 
                        } 
                    } catch (WebException webException) {
                        if (webException.Response != null && 
                            webException.Response is HttpWebResponse)
                        {
                            throw new WebException(webException.Message,
                                                   null, 
                                                   webException.Status,
                                                   new FtpWebResponse((HttpWebResponse)webException.Response), 
                                                   webException.InternalStatus); 
                        }
                        throw; 
                    }
                }
                else{
                    castedAsyncResult.InternalWaitForCompletion(); 
                    castedAsyncResult.EndCalled = true;
                    CheckError(); 
                } 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetResponse", exception); 
                throw;
            } finally {
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse");
                if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetResponse", ""); 
            }
            return m_FtpWebResponse; 
        } 

 
        /// 
        /// Used to query for the Request stream of an FTP Request
        /// 
        public override Stream GetRequestStream() { 
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetRequestStream", "");
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "GetRequestStream", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream"); 

            try { 
                if (m_GetRequestStreamStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                }
                m_GetRequestStreamStarted = true; 
                if (!m_MethodInfo.IsUpload) {
                    throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget)); 
                } 
                CheckError();
 
                m_StartTime = DateTime.UtcNow;
                m_RemainingTimeout = Timeout;

                // We don't really need this variable, but we just need 
                // to call the property to measure its execution time
                ServicePoint servicePoint = ServicePoint; 
 
                if (Timeout != System.Threading.Timeout.Infinite)
                { 
                    m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);

                    if(m_RemainingTimeout <= 0){
                        throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout); 
                    }
                } 
 

                if (ServicePoint.InternalProxyServicePoint) 
                {
                    HttpWebRequest httpWebRequest = GetHttpWebRequest();
                    if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest);
                    m_Stream = httpWebRequest.GetRequestStream(); 
                } else {
                    FinishRequestStage(RequestStage.RequestStarted); 
                    SubmitRequest(false); 
                    FinishRequestStage(RequestStage.WriteReady);
                    CheckError(); 
                }

                if(m_Stream.CanTimeout) {
                    m_Stream.WriteTimeout = ReadWriteTimeout; 
                    m_Stream.ReadTimeout = ReadWriteTimeout;
                } 
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "GetRequestStream", exception);
                throw; 
            } finally {

                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream");
                if(Logging.On)Logging.Exit(Logging.Web, this, "GetRequestStream", ""); 
            }
            return m_Stream; 
        } 

        ///  
        /// Used to query for the Request stream of an FTP Request [async version]
        /// 
        [HostProtection(ExternalThreading=true)]
        public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) { 
            if(Logging.On)Logging.Enter(Logging.Web, this, "BeginGetRequestStream", "");
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "BeginGetRequestStream", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream"); 

            ContextAwareResult asyncResult = null; 

            try {
                if (m_GetRequestStreamStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall)); 
                }
                m_GetRequestStreamStarted = true; 
                if (!m_MethodInfo.IsUpload) { 
                    throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
                } 
                CheckError();

                if (ServicePoint.InternalProxyServicePoint)
                { 
                    HttpWebRequest httpWebRequest = GetHttpWebRequest();
                    if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest); 
                    asyncResult = (ContextAwareResult)httpWebRequest.BeginGetRequestStream(callback, state); 
                }
                else 
                {
                    FinishRequestStage(RequestStage.RequestStarted);
                    asyncResult = new ContextAwareResult(true, true, this, state, callback);
                    lock (asyncResult.StartPostingAsyncOp()) 
                    {
                        m_WriteAsyncResult = asyncResult; 
                        SubmitRequest(true); 
                        asyncResult.FinishPostingAsyncOp();
                        FinishRequestStage(RequestStage.CheckForError); 
                    }
                }
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetRequestStream", exception); 
                throw;
            } finally { 
 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream");
                if(Logging.On)Logging.Exit(Logging.Web, this, "BeginGetRequestStream", ""); 
            }
            return asyncResult;
        }
 
        public override Stream EndGetRequestStream(IAsyncResult asyncResult) {
 
            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetRequestStream", ""); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream");
 
            Stream requestStream = null;

            try {
                // parameter validation 
                if (asyncResult==null) {
                    throw new ArgumentNullException("asyncResult"); 
                } 

                LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult; 
                if ((castedAsyncResult==null) ||
                    (HttpProxyMode?(castedAsyncResult.AsyncObject!=this.GetHttpWebRequest()):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")); 
                }
 
                if (HttpProxyMode) {
                    requestStream = GetHttpWebRequest().EndGetRequestStream(asyncResult);
                } else {
                    castedAsyncResult.InternalWaitForCompletion(); 
                    castedAsyncResult.EndCalled = true;
                    CheckError(); 
                    requestStream = m_Stream; 
                    castedAsyncResult.EndCalled = true;
                } 

                if(requestStream.CanTimeout) {
                    requestStream.WriteTimeout = ReadWriteTimeout;
                    requestStream.ReadTimeout = ReadWriteTimeout; 
                }
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetRequestStream", exception); 
                throw;
            } finally { 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream");
                if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetRequestStream", "");
            }
            return requestStream; 
        }
 
        // 
        // NOTE1: The caller must synchronize access to SubmitRequest(), only one call is even allowed for a particular request!
        // NOTE2: This method eats all exceptions so the caller must rethrow them 
        //
        private void SubmitRequest(bool async) {
            try {
                m_Async = async; 

                if (CheckCacheRetrieveBeforeSubmit()) 
                { 
                    RequestCallback(null);
                    return; 
                }

                //  This is the only place touching m_ConnectionPool
                if (m_ConnectionPool == null) 
                    m_ConnectionPool = ConnectionPoolManager.GetConnectionPool(ServicePoint, GetConnectionGroupLine(), m_CreateConnectionCallback);
 
                // 
                // FYI: Will do 2 attempts max as per AttemptedRecovery
                // 
                Stream  stream;

                while(true)
                { 
                    FtpControlStream connection = m_Connection;
 
                    if (connection == null) 
                    {
                        connection = QueueOrCreateConnection(); 
                        if (connection == null)
                            return;
                    }
 
                    if(!async){
                        if (Timeout != System.Threading.Timeout.Infinite) 
                        { 
                            m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
 
                            if(m_RemainingTimeout <= 0){
                                throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
                            }
                        } 
                    }
 
                    GlobalLog.Print("Request being submitted"+ValidationHelper.HashString(this)); 
                    connection.SetSocketTimeoutOption(SocketShutdown.Both, RemainingTimeout, false);
 
                    try {
                        stream = TimedSubmitRequestHelper(async);
                    } catch (Exception e) {
                        if (AttemptedRecovery(e)){ 
                            if(!async){
                                if (Timeout != System.Threading.Timeout.Infinite) 
                                { 
                                    m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
                                    if(m_RemainingTimeout <= 0){ 
                                        throw;
                                    }
                                }
                            } 
                            continue;
                        } 
                        throw; 
                    }
                    // no retry needed 
                    break;
                }
            } catch (WebException webException) {
                //if this was a timeout, throw a timeout exception 
                IOException ioEx = webException.InnerException as IOException;
                if(ioEx != null){ 
                    SocketException ---- = ioEx.InnerException as SocketException; 
                     if(---- != null){
                        if (----.ErrorCode == (int)SocketError.TimedOut) { 
                            SetException(new WebException(SR.GetString(SR.net_timeout), WebExceptionStatus.Timeout));
                        }
                    }
                } 

                SetException(webException); 
            } 
            catch (Exception exception) {
                SetException(exception); 
            }
        }

        // 
        //
        // 
        private FtpControlStream QueueOrCreateConnection() 
        {
            FtpControlStream connection = (FtpControlStream) m_ConnectionPool.GetConnection((object)this, (m_Async ? m_AsyncCallback : null), (m_Async ? -1: RemainingTimeout)); 

            if (connection == null)
            {
                GlobalLog.Assert(m_Async, "QueueOrCreateConnection|m_ConnectionPool.GetConnection() returned null on a [....] Request."); 
                return null;
            } 
 
            lock (m_SyncObject)
            { 
                if (m_Aborted)
                {
                    if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection)));
                    m_ConnectionPool.PutConnection(connection, this, RemainingTimeout); 
                    CheckError(); //must throw
                    throw new InternalException(); 
                } 
                m_Connection = connection;
                if (Logging.On) Logging.Associate(Logging.Web, this, m_Connection); 
            }
            return connection;
        }
        // 
        //
        private Stream TimedSubmitRequestHelper(bool async) 
        { 
            if(async) {
                // non-null in the case of re-submit (recovery) 
                if (m_RequestCompleteAsyncResult == null)
                    m_RequestCompleteAsyncResult = new LazyAsyncResult(null, null, null);
                return m_Connection.SubmitRequest(this, true, true);
            } 

            Stream stream = null; 
            bool timedOut = false; 
            TimerThread.Timer timer = TimerQueue.CreateTimer(m_TimerCallback, null);
            try { 
                stream = m_Connection.SubmitRequest(this, false, true);
            }
            catch (Exception exception) {
                if (!(exception is SocketException || exception is ObjectDisposedException) || !timer.HasExpired) { 
                    timer.Cancel();
                    throw; 
                } 

                timedOut = true; 
            }

            if (timedOut || !timer.Cancel()) {
                m_TimedOut = true; 
                throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
            } 
 
            if (stream != null)
            { 
                lock (m_SyncObject)
                {
                    if (m_Aborted)
                    { 
                        ((ICloseEx)stream).CloseEx(CloseExState.Abort|CloseExState.Silent);
                        CheckError(); //must throw 
                        throw new InternalException(); //consider replacing this on Assert 
                    }
                    m_Stream = stream; 
                }
            }

            return stream; 
        }
 
        ///  
        ///    Because this is called from the timer thread, neither it nor any methods it calls can call user code.
        ///  
        private void TimerCallback(TimerThread.Timer timer, int timeNoticed, object context) {
            GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::TimerCallback");
            FtpControlStream connection = m_Connection;
            if (connection != null) { 
                GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::TimerCallback aborting connection");
                connection.AbortConnect(); 
            } 
        }
 
        private TimerThread.Queue TimerQueue {
            get {
                if (m_TimerQueue == null) {
                    m_TimerQueue = TimerThread.GetOrCreateQueue(RemainingTimeout); 
                }
 
                return m_TimerQueue; 
            }
        } 

        /// 
        ///    Returns true if we should restart the request after an error
        ///  
        private bool AttemptedRecovery(Exception e) {
            // The first 'if' is just checking whether the exception is thrown due to the 
            // relogin failure which is a recoverable error 
            if (!(e is WebException && ((WebException)e).InternalStatus == WebExceptionInternalStatus.Isolated))
            { 
                if (e is ThreadAbortException
                    || e is StackOverflowException
                    || e is OutOfMemoryException
                    || m_OnceFailed 
                    || m_Aborted
                    || m_TimedOut 
                    || m_Connection==null 
                    || !m_Connection.RecoverableFailure)
                { 
                    return false;
                }
                m_OnceFailed = true;
            } 

            lock (m_SyncObject) { 
                if (m_ConnectionPool != null && m_Connection != null) { 
                    m_Connection.CloseSocket();
                    if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(m_Connection))); 
                    m_ConnectionPool.PutConnection(m_Connection, this, RemainingTimeout);
                    m_Connection = null;
                } else {
                    return false; 
                }
            } 
            return true; 
        }
 
        /// 
        ///    Updates and sets our exception to be thrown
        /// 
        private void SetException(Exception exception) { 

            GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SetException"); 
 
            if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
                m_Exception = exception; 
                throw exception;
            }

            FtpControlStream connection = m_Connection; 
            if (m_Exception == null) {
                if (exception is WebException) 
                { 
                    EnsureFtpWebResponse(exception);
                    m_Exception = new WebException(exception.Message, null, ((WebException)exception).Status, m_FtpWebResponse); 
                }
                else if (exception is AuthenticationException || exception is SecurityException)
                {
                    m_Exception = exception; 
                }
                else if (connection!= null && connection.StatusCode != FtpStatusCode.Undefined) 
                { 
                    EnsureFtpWebResponse(exception);
                    m_Exception = new WebException(SR.GetString(SR.net_servererror, connection.StatusLine), exception, WebExceptionStatus.ProtocolError, m_FtpWebResponse); 
                } else
                {
                    m_Exception = new WebException(exception.Message, exception);
                } 

                if (connection != null && m_FtpWebResponse != null) 
                    m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage); 
            }
        } 

        /// 
        ///    Opposite of SetException, rethrows the exception
        ///  
        private void CheckError() {
            if (m_Exception != null) { 
                throw m_Exception; 
            }
        } 

        // Return null only on [....] (if we're on the [....] thread).  Otherwise throw if no context is available.
        //
        // 

        internal override ContextAwareResult GetWritingContext() 
        { 
            if (m_ReadAsyncResult != null && m_ReadAsyncResult is ContextAwareResult)
                return (ContextAwareResult)m_ReadAsyncResult; 
            else if (m_WriteAsyncResult != null)
                return m_WriteAsyncResult;

            // [....]. 
            GlobalLog.ThreadContract(ThreadKinds.User | ThreadKinds.[....], "FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetWritingContext");
            return null; 
        } 

        // 
        //    Provides an abstract way of having Async code callback into the request (saves a delegate)
        //
        //    ATTN this method is also called on [....] path when either command or data stream gets closed
        //    Consider: Revisit the design of ftp streams 
        //
        internal override void RequestCallback(object obj) 
        { 
            if (m_Async)
                AsyncRequestCallback(obj); 
            else
                SyncRequestCallback(obj);
        }
        // 
        // Only executed for [....] requests when the pipline is completed
        // 
        private void SyncRequestCallback(object obj) 
        {
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SyncRequestCallback", "#"+ValidationHelper.HashString(obj)); 
            RequestStage stageMode = RequestStage.CheckForError;
            try {

                bool completedRequest = obj == null; 
                Exception exception = obj as Exception;
 
                GlobalLog.Print("SyncRequestCallback() exp:"+ValidationHelper.HashString(exception)+" completedRequest:"+ValidationHelper.HashString(completedRequest)); 

 
                if (exception != null)
                {
                    SetException(exception);
                } 
                else if (!completedRequest)
                { 
                    throw new InternalException(); 
                }
                else 
                {
                    // a signal on current pipeline completion
                    FtpControlStream connection = m_Connection;
 
                    bool isRevalidatedOrRetried = false;
                    if (connection != null) 
                    { 
                        EnsureFtpWebResponse(null);
 
                        // This to update response status and exit message if any
                        // Note that due to a design of FtpControlStream the status 221 "Service closing control connection" is always suppresses.
                        m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);
 
                        isRevalidatedOrRetried =!m_CacheDone &&
                                                (CacheProtocol.ProtocolStatus == CacheValidationStatus.Continue || CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer); 
 
                        // This is for [....] Upload commands that do not get chance hit GetResponse loop
                        if (m_MethodInfo.IsUpload) 
                        {
                            CheckCacheRetrieveOnResponse();
                            CheckCacheUpdateOnResponse();
                        } 
                    }
 
                    if (!isRevalidatedOrRetried) 
                        stageMode = RequestStage.ReleaseConnection;
                } 
            }
            catch (Exception exception) {
                SetException(exception);
            } 
            finally {
                FinishRequestStage(stageMode); 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SyncRequestCallback"); 
                CheckError(); //will throw on error
            } 
        }
        //
        // Only executed for Async requests
        // 
        private void AsyncRequestCallback(object obj)
        { 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::AsyncRequestCallback", "#"+ValidationHelper.HashString(obj)); 
            RequestStage stageMode = RequestStage.CheckForError;
 
            try {

                FtpControlStream connection;
                connection = obj as FtpControlStream; 
                FtpDataStream stream = obj as FtpDataStream;
                Exception exception = obj as Exception; 
 
                bool completedRequest = (obj == null);
 
                GlobalLog.Print("AsyncRequestCallback()  stream:"+ValidationHelper.HashString(stream)+" conn:"+ValidationHelper.HashString(connection)+" exp:"+ValidationHelper.HashString(exception)+" completedRequest:"+ValidationHelper.HashString(completedRequest));

                while (true)
                { 
                    if (exception != null)
                    { 
                        if (AttemptedRecovery(exception)) 
                        {
                            connection = QueueOrCreateConnection(); 
                            if (connection == null)
                                return;
                            exception = null;
                        } 
                        if (exception != null)
                        { 
                            SetException(exception); 
                            break;
                        } 
                    }

                    if (connection != null)
                    { 
                        lock(m_SyncObject)
                        { 
                            if (m_Aborted) 
                            {
                                if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection))); 
                                m_ConnectionPool.PutConnection(connection, this, Timeout);
                                break;
                            }
                            m_Connection = connection; 
                            if (Logging.On) Logging.Associate(Logging.Web, this, m_Connection);
                        } 
 
                        try {
                            stream = (FtpDataStream)TimedSubmitRequestHelper(true); 
                        } catch (Exception e) {
                            exception = e;
                            continue;
                        } 
                        return;
                    } 
                    else if (stream != null) 
                    {
                        lock (m_SyncObject) 
                        {
                            if (m_Aborted)
                            {
                                ((ICloseEx)stream).CloseEx(CloseExState.Abort|CloseExState.Silent); 
                                break;
                            } 
                            m_Stream = stream; 
                        }
 
                        stream.SetSocketTimeoutOption(SocketShutdown.Both, Timeout, true);
                        EnsureFtpWebResponse(null);
                        // This one may update the Stream member on m_FtpWebResponse based on the CacheProtocol feedback.
                        CheckCacheRetrieveOnResponse(); 
                        CheckCacheUpdateOnResponse();
 
                        stageMode = stream.CanRead? RequestStage.ReadReady: RequestStage.WriteReady; 
                    }
                    else if (completedRequest) 
                    {
                        connection = m_Connection;

                        bool isRevalidatedOrRetried = false; 
                        if (connection != null)
                        { 
                            EnsureFtpWebResponse(null); 

                            // This to update response status and exit message if any 
                            // Note that due to a design of FtpControlStream the status 221 "Service closing control connection" is always suppresses.
                            m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);

                            isRevalidatedOrRetried =!m_CacheDone && 
                                                    (CacheProtocol.ProtocolStatus == CacheValidationStatus.Continue || CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer);
 
                            lock (m_SyncObject) 
                            {
                                if(!CheckCacheRetrieveOnResponse()) 
                                    continue;

                                if (m_FtpWebResponse.IsFromCache)
                                    isRevalidatedOrRetried = false; 

                                CheckCacheUpdateOnResponse(); 
                            } 
                        }
 
                        if (!isRevalidatedOrRetried)
                            stageMode = RequestStage.ReleaseConnection;
                    }
                    else 
                    {
                        throw new InternalException(); 
                    } 
                    break;
                } 
            }
            catch (Exception exception)
            {
                SetException(exception); 
            }
            finally { 
                FinishRequestStage(stageMode); 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::AsyncRequestCallback");
            } 
        }

        //
        // 
        //
        private enum RequestStage { 
            CheckForError   = 0,// Do nothing except if there is an error then auto promote to ReleaseConnection 
            RequestStarted,     // Mark this request as started
            WriteReady,         // First half is done, i.e. either writer or response stream. This is always assumed unless Started or CheckForError 
            ReadReady,          // Second half is done, i.e. the read stream can be accesses.
            ReleaseConnection   // Release the control connection (request is read i.e. done-done)
        }
        // 
        // Returns a previous stage
        // 
        private RequestStage FinishRequestStage(RequestStage stage) 
        {
            GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::FinishRequestStage : stage="+stage); 
            if (m_Exception != null)
                stage = RequestStage.ReleaseConnection;

            RequestStage     prev; 
            LazyAsyncResult  writeResult;
            LazyAsyncResult  readResult; 
            FtpControlStream connection; 

            lock (m_SyncObject) 
            {
                prev = m_RequestStage;

                if (stage == RequestStage.CheckForError) 
                    return prev;
 
                if (prev == RequestStage.ReleaseConnection && 
                    stage == RequestStage.ReleaseConnection)
                { 
                    return RequestStage.ReleaseConnection;
                }

                if (stage > prev) 
                    m_RequestStage = stage;
 
                if (stage <= RequestStage.RequestStarted) 
                    return prev;
 
                writeResult  = m_WriteAsyncResult;
                readResult   = m_ReadAsyncResult;
                connection   = m_Connection;
 
                if (stage == RequestStage.ReleaseConnection)
                { 
                    if (m_Exception == null && 
                        !m_Aborted &&
                        prev != RequestStage.ReadReady && 
                        this.m_MethodInfo.IsDownload &&
                        !m_FtpWebResponse.IsFromCache)
                    {
                        return prev; 
                    }
                    if (m_Exception != null || !(m_FtpWebResponse.IsFromCache && !KeepAlive)) 
                        m_Connection = null; 
                }
            } 

            try {
                // First check to see on releasing the connection
                if ((stage == RequestStage.ReleaseConnection || 
                     prev  == RequestStage.ReleaseConnection)
                    && connection != null) 
                { 
                    try {
                        if (m_Exception != null) 
                        {
                            connection.Abort(m_Exception);
                        }
                        else if (m_FtpWebResponse.IsFromCache && !KeepAlive) 
                        {
                            // This means the response has been revalidated and found as good means the commands pipleline is completed. 
                            // Now if this request was NOT KeepAlive we want to be fair and close the control connection. 
                            // That becomes unnecessary complicated in the async case to support "QUIT" command semantic, so simply close the socket
                            // and let pool collect the object. 
                            connection.Quit();
                        }
                    } finally {
                        if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection))); 
                        m_ConnectionPool.PutConnection(connection, this, RemainingTimeout);
                        if (m_Async) 
                            if (m_RequestCompleteAsyncResult != null) 
                                m_RequestCompleteAsyncResult.InvokeCallback();
                    } 
                }
                return prev;
            }
            finally { 
                try {
                    // In any case we want to signal the writer if came here 
                    if (stage >= RequestStage.WriteReady) { 
                        // If writeResult == null and this is an upload request, it means
                        // that the user has called GetResponse() without calling 
                        // GetRequestStream() first. So they are not interested in a
                        // stream. Therefore we close the stream so that the
                        // request/pipeline can continue
                        if (m_MethodInfo.IsUpload && !m_GetRequestStreamStarted) 
                        {
                            if (m_Stream != null) 
                                m_Stream.Close(); 
                        }
                        else if (writeResult != null && !writeResult.InternalPeekCompleted) 
                            writeResult.InvokeCallback();
                    }
                }
                finally { 
                    // The response is ready either with or without a stream
                    if (stage >= RequestStage.ReadReady && readResult != null && !readResult.InternalPeekCompleted) 
                        readResult.InvokeCallback(); 
                }
            } 
        }

        //
        // Used only in the async case and only for the initial callback from the pool when connection is established. 
        //
        private static void AsyncCallbackWrapper(object request, object state) { 
            FtpWebRequest ftpWebRequest = (FtpWebRequest) request; 
            ftpWebRequest.RequestCallback(state);
        } 

        /// 
        ///    builds networkStream from Socket
        ///  
        private static PooledStream CreateFtpConnection(ConnectionPool pool) {
            return (PooledStream) new FtpControlStream(pool, TimeSpan.MaxValue, false); 
        } 

        ///  
        /// Aborts underlying connection to FTP server (command & data)
        /// 
        public override void Abort()
        { 
            if (m_Aborted)
                return; 
 
            if(Logging.On)Logging.Enter(Logging.Web, this, "Abort", "");
 
            try {

                GlobalLog.Print("FtpWebRequest#"+ValidationHelper.HashString(this)+"::Abort()");
 
                if (HttpProxyMode) {
                    GetHttpWebRequest().Abort(); 
                    return; 
                }
 
                if (CacheProtocol != null)
                    CacheProtocol.Abort();

                Stream stream; 
                FtpControlStream connection;
                lock (m_SyncObject) 
                { 
                    if (m_RequestStage >= RequestStage.ReleaseConnection)
                        return; 
                    m_Aborted = true;
                    stream  = m_Stream;
                    connection = m_Connection;
                    m_Exception =  new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), 
                                                    WebExceptionStatus.RequestCanceled) ;
                } 
 
                if (stream != null)
                { 
                    GlobalLog.Assert(stream is ICloseEx, "FtpWebRequest.Abort()|The m_Stream member is not CloseEx hence the risk of connection been orphaned.");
                    ((ICloseEx)stream).CloseEx(CloseExState.Abort|CloseExState.Silent);
                }
                if (connection != null) 
                    connection.Abort(ExceptionHelper.RequestAbortedException);
 
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "Abort", exception);
                throw; 
            } finally {
                if(Logging.On)Logging.Exit(Logging.Web, this, "Abort", "");
            }
        } 

        ///  
        ///  
        /// 
        /// If KeepAlive is set to false, then the control connection to the server will be closed when the request completes. 
        /// Default is true
        /// 
        /// 
        public bool KeepAlive { 
            get {
                return m_KeepAlive; 
            } 
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                }
                m_KeepAlive = value;
            } 
        }
 
        ///  
        /// True by default, false allows transmission using text mode
        ///  
        public bool UseBinary {
            get {
                return m_Binary;
            } 
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }
                m_Binary = value; 
            }
        }

        ///  
        /// False by default, true enables passive mode communication with server.
        /// This alters the way the client talks with the server, allowing the client 
        /// to initiate the data connection with the server 
        /// 
        public bool UsePassive { 
            get {
                return m_Passive;
            }
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                m_Passive = 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 (m_ClientCertificates == null) {
                    lock (m_SyncObject) { 
                        if (m_ClientCertificates == null) { 
                            m_ClientCertificates = new X509CertificateCollection();
                        } 
                    }
                }
                return m_ClientCertificates;
            } 
            set {
                if (value==null) { 
                    throw new ArgumentNullException("value"); 
                }
                m_ClientCertificates = value; 
            }
        }
#endif // !FEATURE_PAL
 
        /// 
        ///    Set to true if we need SSL 
        ///  
        public bool EnableSsl {
            get { 
                return m_EnableSsl;
            }
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                m_EnableSsl = value; 
            }
        } 


        /// 
        ///     
        ///       A collection of headers, currently nothing is return except an empty collection
        ///     
        ///  
        public override WebHeaderCollection Headers {
            get { 
                if (HttpProxyMode) {
                    return GetHttpWebRequest().Headers;
                }
                if (m_FtpRequestHeaders == null) { 
                    m_FtpRequestHeaders         = new WebHeaderCollection(WebHeaderCollectionType.FtpWebRequest);
                } 
                return m_FtpRequestHeaders; 
            }
            set { 
                if (HttpProxyMode) {
                    GetHttpWebRequest().Headers = value;
                }
                m_FtpRequestHeaders = value; 
            }
        } 
 
        // NOT SUPPORTED method
        public override string ContentType { 
            get {
                throw ExceptionHelper.PropertyNotSupportedException;
            }
            set { 
                throw ExceptionHelper.PropertyNotSupportedException;
            } 
        } 

        // NOT SUPPORTED method 
        public override bool UseDefaultCredentials  {
            get {
                throw ExceptionHelper.PropertyNotSupportedException;
            } 
            set {
                throw ExceptionHelper.PropertyNotSupportedException; 
            } 
        }
 
        // NOT SUPPORTED method
        public override bool PreAuthenticate {
            get {
                throw ExceptionHelper.PropertyNotSupportedException; 
            }
            set { 
                throw ExceptionHelper.PropertyNotSupportedException; 
            }
        } 

        /// 
        ///    True if a request has been submitted (ie already active)
        ///  
        private bool InUse {
            get { 
                if (m_GetRequestStreamStarted || m_GetResponseStarted) { 
                    return true;
                } else { 
                    return false;
                }
            }
        } 

        ///  
        ///    True if request is just wrapping HttpWebRequest 
        /// 
        private bool HttpProxyMode { 
            get {
                return (m_HttpWebRequest != null);
            }
        } 

 
        ///  
        ///    Creates an FTP WebResponse based off the responseStream and our active Connection
        ///  
        private void EnsureFtpWebResponse(Exception exception)
        {
            if (m_FtpWebResponse == null || (m_FtpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && m_Stream != null))
            { 
                lock (m_SyncObject) {
                    if (m_FtpWebResponse == null || (m_FtpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && m_Stream != null)) 
                    { 
                        Stream responseStream = m_Stream;
 
                        if (m_MethodInfo.IsUpload) {
                            responseStream = null;
                        }
 
                        if(m_Stream != null && m_Stream.CanRead && m_Stream.CanTimeout)
                        { 
                            m_Stream.ReadTimeout = ReadWriteTimeout; 
                            m_Stream.WriteTimeout = ReadWriteTimeout;
                        } 

                        FtpControlStream connection = m_Connection;
                        long contentLength = connection != null? connection.ContentLength: -1;
 
                        if (responseStream == null)
                        { 
 
                            // If the last command was SIZE, we set the ContentLength on
                            // the FtpControlStream to be the size of the file returned in the 
                            // response. We should propagate that file size to the response so
                            // users can access it. This also maintains the compatibility with
                            // HTTP when returning size instead of content.
                            if (contentLength < 0) 
                                contentLength = 0;
                        } 
 
                        if (m_FtpWebResponse != null)
                        { 
                            m_FtpWebResponse.SetResponseStream(responseStream);
                        }
                        else
                        { 
                            if (connection != null)
                                m_FtpWebResponse = new FtpWebResponse(responseStream, contentLength, connection.ResponseUri, connection.StatusCode, connection.StatusLine, connection.LastModified, connection.BannerMessage, connection.WelcomeMessage, connection.ExitMessage); 
                            else 
                                m_FtpWebResponse = new FtpWebResponse(responseStream, -1, m_Uri, FtpStatusCode.Undefined, null, DateTime.Now, null, null, null);
                        } 
                    }
                }
            }
 
            GlobalLog.Print("FtpWebRequest#"+ValidationHelper.HashString(this)+"::EnsureFtpWebResponse returns #"+ValidationHelper.HashString(m_FtpWebResponse)+" with stream#"+ValidationHelper.HashString(m_FtpWebResponse.m_ResponseStream));
            return; 
        } 

        ///  
        ///    Creates a HttpWebRequest
        /// 
        private HttpWebRequest GetHttpWebRequest() {
            lock (m_SyncObject) { 
                if (m_HttpWebRequest == null) {
                    if (m_ContentOffset > 0) { 
                        throw new InvalidOperationException(SR.GetString(SR.net_ftp_no_offsetforhttp)); 
                    }
 
                    if (!m_MethodInfo.HasHttpCommand)
                        throw new InvalidOperationException(SR.GetString(SR.net_ftp_no_http_cmd));

                    m_HttpWebRequest = new HttpWebRequest(m_Uri, ServicePoint); 
                    m_HttpWebRequest.Credentials = Credentials;
                    m_HttpWebRequest.InternalProxy = m_Proxy; 
                    m_HttpWebRequest.KeepAlive = KeepAlive; 
                    m_HttpWebRequest.Timeout = Timeout;
                    m_HttpWebRequest.Method = m_MethodInfo.HttpCommand; 
                    m_HttpWebRequest.CacheProtocol = CacheProtocol;
                    RequestCacheLevel effectiveLevel;
                    if (CachePolicy == null)
                        effectiveLevel = RequestCacheLevel.BypassCache; 
                    else
                        effectiveLevel = CachePolicy.Level; 
 
                    // Cannot support revalidate through the proxy
                    if (effectiveLevel == RequestCacheLevel.Revalidate) 
                        effectiveLevel = RequestCacheLevel.Reload;
                    m_HttpWebRequest.CachePolicy = new HttpRequestCachePolicy((HttpRequestCacheLevel)effectiveLevel);

                    //disable cache protocol on that class since we are proxying through HTTP 
                    CacheProtocol = null;
 
                } 
            }
            return m_HttpWebRequest; 
        }


        ///  
        ///    Generates a string that
        ///     allows a Connection to remain unique for user 
        ///     this is needed to prevent multiple users from 
        ///     using the same sockets after they mess with things
        ///  
        private string GetConnectionGroupLine() {
            GlobalLog.Print("GetConnectionGroupLine");
            return ConnectionGroupName + "_" + GetUserString();
        } 

 
        ///  
        ///    Returns username string
        ///  
        internal string GetUserString() {
            string name = null;
            if (this.Credentials != null) {
                NetworkCredential networkCreds = this.Credentials.GetCredential(m_Uri, "basic"); 
                if (networkCreds != null) {
                    name = networkCreds.InternalGetUserName(); 
                    string domain = networkCreds.InternalGetDomain(); 
                    if (!ValidationHelper.IsBlankString(domain)) {
                        name = domain+"\\"+name; 
                    }
                }
            }
            return name == null? null: (String.Compare(name,"anonymous", StringComparison.InvariantCultureIgnoreCase) == 0? null: name); 
        }
 
        // 
        // This method may be invoked as part of the request submission but
        // before the response is received 
        // Return:
        // - True       = Use CacheProtocol properties to create the cached response
        // - False      = Proceed with the request submission
        private bool CheckCacheRetrieveBeforeSubmit() { 

            if (CacheProtocol == null || m_CacheDone) { 
                m_CacheDone = true; 
                return false;
            } 

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse ||
                CacheProtocol.ProtocolStatus == CacheValidationStatus.DoNotTakeFromCache)
            { 
                // Re-entry into a new pipeline on failed revalidate or combining cached and live streams
                return false; 
            } 

            Uri cacheUri = RequestUri; 
            string username = GetUserString();
            if(username != null)
                username = Uri.EscapeDataString(username);
 
            if (cacheUri.Fragment.Length != 0 || username != null)
            { 
                if (username == null) 
                    cacheUri = new Uri(cacheUri.GetParts(UriComponents.AbsoluteUri & ~(UriComponents.Fragment|UriComponents.UserInfo), UriFormat.SafeUnescaped));
                else 
                {
                    username =  cacheUri.GetParts((UriComponents.Scheme | UriComponents.KeepDelimiter), UriFormat.SafeUnescaped) + username + '@';
                    username += cacheUri.GetParts((UriComponents.Host | UriComponents.Port | UriComponents.Path | UriComponents.Query), UriFormat.SafeUnescaped);
                    cacheUri = new Uri(username); 
                }
            } 
 
            CacheProtocol.GetRetrieveStatus(cacheUri, this);
 
            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) {
                throw CacheProtocol.ProtocolException;
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) {
                return false; 
            } 

            if (m_MethodInfo.Operation != FtpOperation.DownloadFile) { 
                throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_command));
            }

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.ReturnCachedResponse) 
            {
                // If we take it from cache, we have to kick in response processing 
                // The _CacheStream is good to return as the response stream. 
                FtpRequestCacheValidator ctx = (FtpRequestCacheValidator) CacheProtocol.Validator;
                m_FtpWebResponse = new FtpWebResponse(CacheProtocol.ResponseStream, 
                                                      CacheProtocol.ResponseStreamLength,
                                                      RequestUri,
                                                      UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData,
                                                      (UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData).ToString(), 
                                                      ctx.CacheEntry.LastModifiedUtc == DateTime.MinValue? DateTime.Now: ctx.CacheEntry.LastModifiedUtc.ToLocalTime(),
                                                      string.Empty, 
                                                      string.Empty, 
                                                      string.Empty);
 
                m_FtpWebResponse.InternalSetFromCache = true;
                m_FtpWebResponse.InternalSetIsCacheFresh = (ctx.CacheFreshnessStatus != CacheFreshnessStatus.Stale);
            }
            return true; 
        }
 
        // 
        // 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() { 

            if (CacheProtocol == null || m_CacheDone) { 
                return true; 
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.Continue)
            {
                // cache has been already revalidated proceed with cache update
                return true; 
            }
 
            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "CheckCacheRetrieveOnResponse", CacheProtocol.ProtocolException);
                throw CacheProtocol.ProtocolException; 
            }

            // At this point we dont have the real data stream, hence passing null and updating it later
            CacheProtocol.GetRevalidateStatus(m_FtpWebResponse, null); 

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer) 
            { 
                if (m_FtpWebResponse != null)
                    m_FtpWebResponse.SetResponseStream(null); //prevent from advancing commands pipeline 
                // Try to resubmit or fail
                return false;
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse)
            { 
                // Proceed with the requesting the real server data stream 
                return false;
            } 

            if (m_MethodInfo.Operation != FtpOperation.DownloadFile)
            {
                // This should never happen in real life 
                throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_command));
            } 
 

            FtpRequestCacheValidator ctx = (FtpRequestCacheValidator) CacheProtocol.Validator; 

            FtpWebResponse oldResponse = m_FtpWebResponse;
            m_Stream = CacheProtocol.ResponseStream;
            m_FtpWebResponse = new FtpWebResponse(CacheProtocol.ResponseStream, 
                                                  CacheProtocol.ResponseStreamLength,
                                                  RequestUri, 
                                                  UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData, 
                                                  (UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData).ToString(),
                                                  ctx.CacheEntry.LastModifiedUtc == DateTime.MinValue? DateTime.Now: ctx.CacheEntry.LastModifiedUtc.ToLocalTime(), 
                                                  string.Empty,
                                                  string.Empty,
                                                  string.Empty);
 
            m_FtpWebResponse.InternalSetFromCache = true;
            m_FtpWebResponse.InternalSetIsCacheFresh = CacheProtocol.IsCacheFresh; 
 
            oldResponse.Close();
            return true; 
        }


 
        //
        // This will decide on cache update and construct the effective response stream 
        // 
        private void CheckCacheUpdateOnResponse()
        { 
            if (CacheProtocol == null || m_CacheDone) {
                return;
            }
            m_CacheDone = true; 

            if (m_Connection != null) 
            { 
                m_FtpWebResponse.UpdateStatus(m_Connection.StatusCode, m_Connection.StatusLine, m_Connection.ExitMessage);
                if (m_Connection.StatusCode == FtpStatusCode.OpeningData && m_FtpWebResponse.ContentLength == 0) 
                    m_FtpWebResponse.SetContentLength(m_Connection.ContentLength);
            }

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse) 
            {
                // Note we already asked for a file restart 
                // The only problem is that we could not create the combined stream sooner. 
                m_Stream = new CombinedReadStream(CacheProtocol.Validator.CacheStream, m_FtpWebResponse.GetResponseStream());
                // 
                // For consistent user experience we always supply DataAlreadyOpen status for a cached response.
                //
                FtpStatusCode rightStatus = UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData;
 
                m_FtpWebResponse.UpdateStatus(rightStatus, rightStatus.ToString(), string.Empty);
                m_FtpWebResponse.SetResponseStream(m_Stream); 
            } 

            if (CacheProtocol.GetUpdateStatus(m_FtpWebResponse, m_FtpWebResponse.GetResponseStream()) == CacheValidationStatus.UpdateResponseInformation) 
            {
                m_Stream = CacheProtocol.ResponseStream;
                m_FtpWebResponse.SetResponseStream(m_Stream);
            } 
            else if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail)
                throw CacheProtocol.ProtocolException; 
        } 

        internal void DataStreamClosed(CloseExState closeState) 
        {
            if ((closeState & CloseExState.Abort) == 0)
            {
                if (!m_Async) 
                {
                    if (m_Connection != null) 
                        m_Connection.CheckContinuePipeline(); 
                }
                else 
                {
                    m_RequestCompleteAsyncResult.InternalWaitForCompletion();
                    CheckError();
                } 
            }
            else 
            { 
                FtpControlStream connection = m_Connection;
                if (connection != null) 
                    connection.Abort(ExceptionHelper.RequestAbortedException);
            }
        }
    }  // class FtpWebRequest 

    // 
    // Class used by the WebRequest.Create factory to create FTP requests 
    //
    internal class FtpWebRequestCreator : IWebRequestCreate { 
        internal FtpWebRequestCreator() {
        }
        public WebRequest Create(Uri uri) {
            return new FtpWebRequest(uri); 
        }
    } // class FtpWebRequestCreator 
 
} //namespace System.Net
 



// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ----------------------------------------------------------------------------- 
//
 
namespace System.Net { 
    using System.Collections;
    using System.IO; 
    using System.Text;
    using System.Net.Sockets;
    using System.Net.Cache;
    using System.Threading; 
    using System.Security;
    using System.Security.Cryptography.X509Certificates ; 
    using System.Security.Permissions; 
    using System.Security.Authentication;
    using System.Globalization; 


    /// 
    /// Allows us to control what the request is used for (based on the type of behavior, 
    ///     that the command calls for)
    ///  
    internal enum FtpOperation { 
        DownloadFile          = 0,
        ListDirectory         = 1, 
        ListDirectoryDetails  = 2,
        UploadFile            = 3,
        UploadFileUnique      = 4,
        AppendFile            = 5, 
        DeleteFile            = 6,
        GetDateTimestamp      = 7, 
        GetFileSize           = 8, 
        Rename                = 9,
        MakeDirectory         = 10, 
        RemoveDirectory       = 11,
        PrintWorkingDirectory = 12,
        Other                 = 13,
    } 

    [Flags] 
    internal enum FtpMethodFlags { 
        None                      = 0x0,
        IsDownload                = 0x1, 
        IsUpload                  = 0x2,
        TakesParameter            = 0x4,
        MayTakeParameter          = 0x8,
        DoesNotTakeParameter      = 0x10, 
        ParameterIsDirectory      = 0x20,
        ShouldParseForResponseUri = 0x40, 
        HasHttpCommand            = 0x80, 
        MustChangeWorkingDirectoryToPath  = 0x100
    } 

    internal class FtpMethodInfo {
        internal string          Method;
        internal FtpOperation    Operation; 
        internal FtpMethodFlags  Flags;
        internal string          HttpCommand; 
 
        internal FtpMethodInfo(string         method,
                               FtpOperation   operation, 
                               FtpMethodFlags flags,
                               string         httpCommand)
        {
            Method      = method; 
            Operation   = operation;
            Flags       = flags; 
            HttpCommand = httpCommand; 
        }
 
        internal bool HasFlag(FtpMethodFlags flags) {
            return (Flags & flags) != 0;
        }
 
        internal bool IsCommandOnly {
            get { return (Flags & (FtpMethodFlags.IsDownload | FtpMethodFlags.IsUpload)) == 0; } 
        } 

        internal bool IsUpload { 
            get { return (Flags & FtpMethodFlags.IsUpload) != 0; }
        }

        internal bool IsDownload { 
            get { return (Flags & FtpMethodFlags.IsDownload) != 0; }
        } 
 
        internal bool HasHttpCommand {
            get { return (Flags & FtpMethodFlags.HasHttpCommand) != 0; } 
        }

        /// 
        ///    True if we should attempt to get a response uri 
        ///    out of a server response
        ///  
        internal bool ShouldParseForResponseUri { 
            get { return (Flags & FtpMethodFlags.ShouldParseForResponseUri) != 0; }
        } 

        internal static FtpMethodInfo GetMethodInfo(string method)  {
            method = method.ToUpper(CultureInfo.InvariantCulture);
            foreach (FtpMethodInfo methodInfo in KnownMethodInfo) 
                if (method == methodInfo.Method)
                    return methodInfo; 
            // We don't support generic methods 
            throw new ArgumentException(SR.GetString(SR.net_ftp_unsupported_method), "method");
        } 

        static readonly FtpMethodInfo[] KnownMethodInfo =
        {
            new FtpMethodInfo(WebRequestMethods.Ftp.DownloadFile, 
                              FtpOperation.DownloadFile,
                              FtpMethodFlags.IsDownload 
                              | FtpMethodFlags.HasHttpCommand 
                              | FtpMethodFlags.TakesParameter,
                              "GET"), 
            new FtpMethodInfo(WebRequestMethods.Ftp.ListDirectory,
                              FtpOperation.ListDirectory,
                              FtpMethodFlags.IsDownload
                              | FtpMethodFlags.MustChangeWorkingDirectoryToPath 
                              | FtpMethodFlags.HasHttpCommand
                              | FtpMethodFlags.MayTakeParameter, 
                              "GET"), 
            new FtpMethodInfo(WebRequestMethods.Ftp.ListDirectoryDetails,
                              FtpOperation.ListDirectoryDetails, 
                              FtpMethodFlags.IsDownload
                              | FtpMethodFlags.MustChangeWorkingDirectoryToPath
                              | FtpMethodFlags.HasHttpCommand
                              | FtpMethodFlags.MayTakeParameter, 
                              "GET"),
            new FtpMethodInfo(WebRequestMethods.Ftp.UploadFile, 
                              FtpOperation.UploadFile, 
                              FtpMethodFlags.IsUpload
                              | FtpMethodFlags.TakesParameter, 
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.UploadFileWithUniqueName,
                              FtpOperation.UploadFileUnique,
                              FtpMethodFlags.IsUpload 
                              | FtpMethodFlags.MustChangeWorkingDirectoryToPath
                              | FtpMethodFlags.DoesNotTakeParameter 
                              | FtpMethodFlags.ShouldParseForResponseUri, 
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.AppendFile, 
                              FtpOperation.AppendFile,
                              FtpMethodFlags.IsUpload
                              | FtpMethodFlags.TakesParameter,
                              null), 
            new FtpMethodInfo(WebRequestMethods.Ftp.DeleteFile,
                              FtpOperation.DeleteFile, 
                              FtpMethodFlags.TakesParameter, 
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.GetDateTimestamp, 
                              FtpOperation.GetDateTimestamp,
                              FtpMethodFlags.TakesParameter,
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.GetFileSize, 
                              FtpOperation.GetFileSize,
                              FtpMethodFlags.TakesParameter, 
                              null), 
            new FtpMethodInfo(WebRequestMethods.Ftp.Rename,
                              FtpOperation.Rename, 
                              FtpMethodFlags.TakesParameter,
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.MakeDirectory,
                              FtpOperation.MakeDirectory, 
                              FtpMethodFlags.TakesParameter
                              | FtpMethodFlags.ParameterIsDirectory, 
                              null), 
            new FtpMethodInfo(WebRequestMethods.Ftp.RemoveDirectory,
                              FtpOperation.RemoveDirectory, 
                              FtpMethodFlags.TakesParameter
                              | FtpMethodFlags.ParameterIsDirectory,
                              null),
            new FtpMethodInfo(WebRequestMethods.Ftp.PrintWorkingDirectory, 
                              FtpOperation.PrintWorkingDirectory,
                              FtpMethodFlags.DoesNotTakeParameter, 
                              null) 
        };
 
    }

    /// 
    /// The FtpWebRequest class implements a basic FTP client 
    /// interface.
    ///  
    public sealed class FtpWebRequest : WebRequest { 
        private object          m_SyncObject;
        private ICredentials    m_AuthInfo; 
        private readonly Uri    m_Uri;
        private FtpMethodInfo   m_MethodInfo;
        private string          m_RenameTo = null;
        private bool            m_GetRequestStreamStarted; 
        private bool            m_GetResponseStarted;
        private DateTime        m_StartTime; 
        private int             m_Timeout = s_DefaultTimeout; 
        private int             m_RemainingTimeout;
        private long            m_ContentLength = 0; 
        private long            m_ContentOffset = 0;
        private IWebProxy       m_Proxy;
#if !FEATURE_PAL
        private X509CertificateCollection m_ClientCertificates; 
#endif // !FEATURE_PAL
        private bool            m_KeepAlive = true; 
        private bool            m_Passive = true; 
        private bool            m_Binary = true;
        private string          m_ConnectionGroupName; 
        private ServicePoint    m_ServicePoint;

        private bool            m_CacheDone; // Not sure why but the command stream wants to notify the request on every pipiline closure closure by invoking RequestCallback.
                                             // m_CacheDone is to facilitate PutConnection decision and to prevent bothering cache protocol when it's all completed. 

        private bool            m_Async; 
        private bool            m_Aborted; 
        private bool            m_TimedOut;
 
        private HttpWebRequest  m_HttpWebRequest;
        private Exception       m_Exception;

        private TimerThread.Queue    m_TimerQueue = s_DefaultTimerQueue; 
        private TimerThread.Callback m_TimerCallback;
 
        private bool                 m_EnableSsl; 
        private bool                 m_ProxyUserSet;
        private ConnectionPool       m_ConnectionPool; 
        private FtpControlStream     m_Connection;
        private Stream               m_Stream;
        private RequestStage         m_RequestStage;
        private bool                 m_OnceFailed; 
        private WebHeaderCollection  m_FtpRequestHeaders;
        private FtpWebResponse       m_FtpWebResponse; 
        private int                  m_ReadWriteTimeout = 5*60*1000;  //5 minutes. 

 
        private ContextAwareResult  m_WriteAsyncResult;
        private LazyAsyncResult     m_ReadAsyncResult;
        private LazyAsyncResult     m_RequestCompleteAsyncResult;
 
        private static readonly GeneralAsyncDelegate m_AsyncCallback = new GeneralAsyncDelegate(AsyncCallbackWrapper);
        private static readonly CreateConnectionDelegate m_CreateConnectionCallback = new CreateConnectionDelegate(CreateFtpConnection); 
        private static readonly NetworkCredential DefaultFtpNetworkCredential = new NetworkCredential("anonymous", "anonymous@", String.Empty); 
        private static readonly int s_DefaultTimeout = WebRequest.DefaultTimeout;
        private static readonly TimerThread.Queue s_DefaultTimerQueue = TimerThread.GetOrCreateQueue(s_DefaultTimeout); 

        // Used by FtpControlStream
        internal FtpMethodInfo MethodInfo {
            get { 
                return m_MethodInfo;
            } 
        } 

        // Used by FtpControlStream 
        internal static NetworkCredential DefaultNetworkCredential{
            get {
                return DefaultFtpNetworkCredential;
            } 
        }
 
        // 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 {
                RequestCachePolicy policy = RequestCacheManager.GetBinding(Uri.UriSchemeFtp).Policy;
                if (policy == null) 
                    return WebRequest.DefaultCachePolicy;
                return policy; 
            } 
            set {
                // 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.UriSchemeFtp);
                RequestCacheManager.SetBinding(Uri.UriSchemeFtp, new RequestCacheBinding(binding.Cache, binding.Validator, value)); 
            }
        } 
 
        /// 
        ///  
        /// Selects upload or download of files. WebRequestMethods.Ftp.DownloadFile is default.
        /// Not allowed to be changed once request is started.
        /// 
        ///  
        public override string Method {
            get { 
                return m_MethodInfo.Method; 
            }
            set { 
                if (String.IsNullOrEmpty(value)) {
                    throw new ArgumentException(SR.GetString(SR.net_ftp_invalid_method_name), "value");
                }
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                try { 
                    m_MethodInfo = FtpMethodInfo.GetMethodInfo(value);
                } catch (ArgumentException) { 
                    throw new ArgumentException(SR.GetString(SR.net_ftp_unsupported_method), "value");
                }
           }
        } 

        ///  
        ///  
        /// Sets the target name for the WebRequestMethods.Ftp.Rename command
        /// Not allowed to be changed once request is started. 
        /// 
        /// 
        public string RenameTo {
            get { 
                return m_RenameTo;
            } 
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }

                if (String.IsNullOrEmpty(value)) {
                    throw new ArgumentException(SR.GetString(SR.net_ftp_invalid_renameto), "value"); 
                }
 
                m_RenameTo = value; 
           }
        } 

        /// 
        /// Used for clear text authentication with FTP server
        ///  
        public override ICredentials Credentials {
            get { 
                return m_AuthInfo; 
            }
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                }
                if (value == null) { 
                    throw new ArgumentNullException("value");
                } 
                if (value is SystemNetworkCredential) { 
                    throw new ArgumentException(SR.GetString(SR.net_ftp_no_defaultcreds), "value");
                } 
                m_AuthInfo = value;
            }
        }
 
        /// 
        /// Gets the Uri used to make the request 
        ///  
        public override Uri RequestUri {
            get { 
                return m_Uri;
            }
        }
 
        /// 
        /// Timeout of the blocking calls such as GetResponse and GetRequestStream (default 100 secs) 
        ///  
        public override int Timeout {
            get { 
                return m_Timeout;
            }
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                if (value<0 && value!=System.Threading.Timeout.Infinite) { 
                    throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_ge_zero));
                } 
                if (m_Timeout != value)
                {
                    m_Timeout = value;
                    m_TimerQueue = null; 
                }
            } 
        } 

        // This can always be calculaed as Remaining = Timeout - (Now - Start) 
        // but we are keeping this for performance reasons (To avoid unnecessary
        // calculations). This can be removed if the performance gains are
        // considered negligible and not necessary
        internal int RemainingTimeout { 
            get {
                return m_RemainingTimeout; 
            } 
        }
 


        /// 
        ///    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 m_ReadWriteTimeout;
            }
            set { 
                if (m_GetResponseStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                if (value<=0 && value!=System.Threading.Timeout.Infinite) {
                    throw new ArgumentOutOfRangeException("value", SR.GetString(SR.net_io_timeout_use_gt_zero)); 
                }
                m_ReadWriteTimeout = value;
            }
        } 

        ///  
        /// Used to specify what offset we will read at 
        /// 
        public long ContentOffset { 
            get {
                return m_ContentOffset;
            }
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                if (value<0) {
                    throw new ArgumentOutOfRangeException("value"); 
                }
                m_ContentOffset = value;
            }
        } 

 
 
        /// 
        /// Gets or sets the data size of to-be uploaded data 
        /// 
        public override long ContentLength {
            get {
                return m_ContentLength; 
            }
            set { 
                m_ContentLength = value; 
            }
        } 

        /// 
        /// Uses an HTTP proxy if needed to send FTP request
        ///  
        public override IWebProxy Proxy {
            get { 
                ExceptionHelper.WebPermissionUnrestricted.Demand(); 
                return m_Proxy;
            } 
            set {
                ExceptionHelper.WebPermissionUnrestricted.Demand();
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }
                m_ProxyUserSet = true; 
                m_Proxy = value; 
                m_ServicePoint = null;
                ServicePoint refreshIt = ServicePoint ; 
            }
        }

        ///  
        /// Allows private ConnectionPool(s) to be used
        ///  
        public override string ConnectionGroupName { 
            get {
                return m_ConnectionGroupName; 
            }
            set {
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }
                m_ConnectionGroupName = value; 
            } 
        }
 
        /// 
        /// Generates a service point for this request, and allows setting of Connection settings
        /// 
        public ServicePoint ServicePoint { 
            get {
                if (m_ServicePoint == null) 
                { 
                    IWebProxy proxy = m_Proxy;
                    if (!m_ProxyUserSet) 
                        proxy = WebRequest.InternalDefaultWebProxy;

                    ServicePoint servicePoint = ServicePointManager.FindServicePoint(m_Uri, proxy);
 
                    lock (m_SyncObject) {
                        if (m_ServicePoint == null) 
                        { 
                            m_ServicePoint = servicePoint;
                            m_Proxy = proxy; 
                        }
                    }
                }
                return m_ServicePoint; 
            }
        } 
 
        internal bool Aborted {
            get { 
                return m_Aborted;
            }
        }
 
        /// 
        ///  
        /// Initializes a new instance of the  
        /// class.
        ///  
        /// 
        internal FtpWebRequest(Uri uri) {
           (new WebPermission(NetworkAccess.Connect, uri)).Demand();
 
           if (Logging.On) Logging.PrintInfo(Logging.Web, this, ".ctor", uri.ToString());
 
           if ((object)uri.Scheme != (object)Uri.UriSchemeFtp) 
               throw new ArgumentOutOfRangeException("uri");
 
            m_TimerCallback = new TimerThread.Callback(TimerCallback);
            m_SyncObject = new object();

            NetworkCredential networkCredential = null; 
            m_Uri = uri;
            m_MethodInfo = FtpMethodInfo.GetMethodInfo(WebRequestMethods.Ftp.DownloadFile); 
            if (m_Uri.UserInfo != null && m_Uri.UserInfo.Length != 0) { 
                string userInfo = m_Uri.UserInfo;
                string username = userInfo; 
                string password = "";
                int index = userInfo.IndexOf(':');
                if (index != -1) {
                    username = Uri.UnescapeDataString(userInfo.Substring(0, index)); 
                    index++; // skip ':'
                    password = Uri.UnescapeDataString(userInfo.Substring(index, userInfo.Length - index)); 
                } 
                networkCredential = new NetworkCredential(username, password);
            } 
            if (networkCredential == null) {
                networkCredential = DefaultFtpNetworkCredential;
            }
            m_AuthInfo = networkCredential; 
            SetupCacheProtocol(m_Uri);
        } 
 

        // 
        // Used to query for the Response of an FTP request
        //
        public override WebResponse GetResponse()
        { 
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetResponse", "");
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "GetResponse", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse"); 

            try { 
                CheckError();

                if (m_FtpWebResponse != null)
                    return m_FtpWebResponse; 

                if (m_GetResponseStarted) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall)); 
                }
 
                m_GetResponseStarted = true;

                m_StartTime = DateTime.UtcNow;
                m_RemainingTimeout = Timeout; 

                // We don't really need this variable, but we just need 
                // to call the property to measure its execution time 
                ServicePoint servicePoint = ServicePoint;
 
                if (Timeout != System.Threading.Timeout.Infinite)
                {
                    m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
 
                    if(m_RemainingTimeout <= 0){
                        throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout); 
                    } 
                }
 
                if (ServicePoint.InternalProxyServicePoint)
                {
                    if (EnableSsl) {
                        m_GetResponseStarted = false; 
                        throw new WebException(SR.GetString(SR.net_ftp_proxy_does_not_support_ssl));
                    } 
 
                    try {
                        HttpWebRequest httpWebRequest = GetHttpWebRequest(); 
                        if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest);

                        m_FtpWebResponse = new FtpWebResponse((HttpWebResponse)httpWebRequest.GetResponse());
                    } catch (WebException webException) { 
                        if (webException.Response != null &&
                            webException.Response is HttpWebResponse) 
                        { 
                            webException = new WebException(webException.Message,
                                null, 
                                webException.Status,
                                new FtpWebResponse((HttpWebResponse)webException.Response),
                                webException.InternalStatus);
                        } 
                        SetException(webException);
                        throw webException; 
                    } 
                    // Catch added to address Bug # 545645
                    catch (InvalidOperationException invalidOpException) 
                    {
                        SetException(invalidOpException);
                        FinishRequestStage(RequestStage.CheckForError);
                        throw; 
                    }
                } 
                else 
                {
                    RequestStage prev = FinishRequestStage(RequestStage.RequestStarted); 
                    if (prev >= RequestStage.RequestStarted)
                    {
                        if (prev < RequestStage.ReadReady)
                        { 
                            lock (m_SyncObject)
                            { 
                                if (m_RequestStage < RequestStage.ReadReady) 
                                    m_ReadAsyncResult = new LazyAsyncResult(null, null, null);
                            } 

                            // GetRequeststream or BeginGetRequestStream has not finished yet?
                            if (m_ReadAsyncResult != null)
                                m_ReadAsyncResult.InternalWaitForCompletion(); 

                            CheckError(); 
                        } 
                    }
                    else 
                    {
                        do
                        {
                            SubmitRequest(false); 
                            if (m_MethodInfo.IsUpload)
                                FinishRequestStage(RequestStage.WriteReady); 
                            else 
                                FinishRequestStage(RequestStage.ReadReady);
                            CheckError(); 
                        } while (!CheckCacheRetrieveOnResponse());

                        EnsureFtpWebResponse(null);
                        // This may update the Stream memeber on m_FtpWebResponse based on the CacheProtocol feedback. 
                        CheckCacheUpdateOnResponse();
 
                        if (m_FtpWebResponse.IsFromCache) 
                            FinishRequestStage(RequestStage.ReleaseConnection);
                    } 
                }
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "GetResponse", exception);
 
                // if m_Exception == null, we are about to throw an exception to the user
                // and we haven't saved the exception, which also means we haven't dealt 
                // with it. So just release the connection and log this for investigation 
                if (m_Exception == null) {
                    if(Logging.On)Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_unexpected_exception, "GetResponse()")); 

                    if (!NclUtilities.IsFatal(exception)){
                        GlobalLog.Assert("Find out why we are getting an unexpected exception.");
                    } 
                    SetException(exception);
                    FinishRequestStage(RequestStage.CheckForError); 
                } 
                throw;
            } finally { 

                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse", "returns #"+ValidationHelper.HashString(m_FtpWebResponse));
                if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponse", "");
            } 
            return m_FtpWebResponse;
        } 
 
        /// 
        ///  
        /// Used to query for the Response of an FTP request [async version]
        /// 
        [HostProtection(ExternalThreading=true)]
        public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) 
        {
            if(Logging.On)Logging.Enter(Logging.Web, this, "BeginGetResponse", ""); 
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "BeginGetResponse", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse");
 
            ContextAwareResult asyncResult;

            try {
                if (m_FtpWebResponse != null) 
                {
                    asyncResult = new ContextAwareResult(this, state, callback); 
                    asyncResult.InvokeCallback(m_FtpWebResponse); 
                    return asyncResult;
                } 

                if (m_GetResponseStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                } 

                m_GetResponseStarted = true; 
                CheckError(); 

                if (ServicePoint.InternalProxyServicePoint) 
                {
                    HttpWebRequest httpWebRequest = GetHttpWebRequest();
                    if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest);
                    asyncResult = (ContextAwareResult)httpWebRequest.BeginGetResponse(callback, state); 
                }
                else 
                { 
                    RequestStage prev = FinishRequestStage(RequestStage.RequestStarted);
                    asyncResult = new ContextAwareResult(true, true, this, state, callback); 
                    m_ReadAsyncResult = asyncResult;

                    if (prev >= RequestStage.RequestStarted)
                    { 
                        // To make sure the context is flowed
                        asyncResult.StartPostingAsyncOp(); 
                        asyncResult.FinishPostingAsyncOp(); 

                        if (prev >= RequestStage.ReadReady) 
                            asyncResult = null;
                        else
                        {
                            lock (m_SyncObject) 
                            {
                                if (m_RequestStage >= RequestStage.ReadReady) 
                                    asyncResult = null;; 
                            }
                        } 

                        if(asyncResult == null)
                        {
                            // need to complete it now 
                            asyncResult = (ContextAwareResult)m_ReadAsyncResult;
                            if (!asyncResult.InternalPeekCompleted) 
                                asyncResult.InvokeCallback(); 
                        }
                    } 
                    else
                    {
                        // Do internal processing in this handler to optimize context flowing.
                        lock (asyncResult.StartPostingAsyncOp()) 
                        {
                            SubmitRequest(true); 
                            asyncResult.FinishPostingAsyncOp(); 
                        }
                        FinishRequestStage(RequestStage.CheckForError); 
                    }
                }
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetResponse", exception); 
                throw;
            } finally { 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse"); 
                if(Logging.On)Logging.Exit(Logging.Web, this, "BeginGetResponse", "");
            } 
            return asyncResult;
        }

        ///  
        /// Returns result of query for the Response of an FTP request [async version]
        ///  
        public override WebResponse EndGetResponse(IAsyncResult asyncResult) { 

            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetResponse", ""); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse");

            try {
                // parameter validation 
                if (asyncResult==null) {
                    throw new ArgumentNullException("asyncResult"); 
                } 
                LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
                if (castedAsyncResult==null) { 
                    throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
                }
                if (HttpProxyMode?(castedAsyncResult.AsyncObject!=this.GetHttpWebRequest()):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")); 
                }
 
                if (HttpProxyMode) {
                    try {
                        CheckError();
                        if (m_FtpWebResponse == null) 
                        {
                            m_FtpWebResponse = new FtpWebResponse((HttpWebResponse)GetHttpWebRequest().EndGetResponse(asyncResult)); 
                        } 
                    } catch (WebException webException) {
                        if (webException.Response != null && 
                            webException.Response is HttpWebResponse)
                        {
                            throw new WebException(webException.Message,
                                                   null, 
                                                   webException.Status,
                                                   new FtpWebResponse((HttpWebResponse)webException.Response), 
                                                   webException.InternalStatus); 
                        }
                        throw; 
                    }
                }
                else{
                    castedAsyncResult.InternalWaitForCompletion(); 
                    castedAsyncResult.EndCalled = true;
                    CheckError(); 
                } 
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetResponse", exception); 
                throw;
            } finally {
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse");
                if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetResponse", ""); 
            }
            return m_FtpWebResponse; 
        } 

 
        /// 
        /// Used to query for the Request stream of an FTP Request
        /// 
        public override Stream GetRequestStream() { 
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetRequestStream", "");
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "GetRequestStream", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream"); 

            try { 
                if (m_GetRequestStreamStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                }
                m_GetRequestStreamStarted = true; 
                if (!m_MethodInfo.IsUpload) {
                    throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget)); 
                } 
                CheckError();
 
                m_StartTime = DateTime.UtcNow;
                m_RemainingTimeout = Timeout;

                // We don't really need this variable, but we just need 
                // to call the property to measure its execution time
                ServicePoint servicePoint = ServicePoint; 
 
                if (Timeout != System.Threading.Timeout.Infinite)
                { 
                    m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);

                    if(m_RemainingTimeout <= 0){
                        throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout); 
                    }
                } 
 

                if (ServicePoint.InternalProxyServicePoint) 
                {
                    HttpWebRequest httpWebRequest = GetHttpWebRequest();
                    if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest);
                    m_Stream = httpWebRequest.GetRequestStream(); 
                } else {
                    FinishRequestStage(RequestStage.RequestStarted); 
                    SubmitRequest(false); 
                    FinishRequestStage(RequestStage.WriteReady);
                    CheckError(); 
                }

                if(m_Stream.CanTimeout) {
                    m_Stream.WriteTimeout = ReadWriteTimeout; 
                    m_Stream.ReadTimeout = ReadWriteTimeout;
                } 
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "GetRequestStream", exception);
                throw; 
            } finally {

                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream");
                if(Logging.On)Logging.Exit(Logging.Web, this, "GetRequestStream", ""); 
            }
            return m_Stream; 
        } 

        ///  
        /// Used to query for the Request stream of an FTP Request [async version]
        /// 
        [HostProtection(ExternalThreading=true)]
        public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state) { 
            if(Logging.On)Logging.Enter(Logging.Web, this, "BeginGetRequestStream", "");
            if(Logging.On)Logging.PrintInfo(Logging.Web, this, "BeginGetRequestStream", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method)); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream"); 

            ContextAwareResult asyncResult = null; 

            try {
                if (m_GetRequestStreamStarted) {
                    throw new InvalidOperationException(SR.GetString(SR.net_repcall)); 
                }
                m_GetRequestStreamStarted = true; 
                if (!m_MethodInfo.IsUpload) { 
                    throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
                } 
                CheckError();

                if (ServicePoint.InternalProxyServicePoint)
                { 
                    HttpWebRequest httpWebRequest = GetHttpWebRequest();
                    if (Logging.On) Logging.Associate(Logging.Web, this, httpWebRequest); 
                    asyncResult = (ContextAwareResult)httpWebRequest.BeginGetRequestStream(callback, state); 
                }
                else 
                {
                    FinishRequestStage(RequestStage.RequestStarted);
                    asyncResult = new ContextAwareResult(true, true, this, state, callback);
                    lock (asyncResult.StartPostingAsyncOp()) 
                    {
                        m_WriteAsyncResult = asyncResult; 
                        SubmitRequest(true); 
                        asyncResult.FinishPostingAsyncOp();
                        FinishRequestStage(RequestStage.CheckForError); 
                    }
                }
            } catch (Exception exception) {
                if(Logging.On)Logging.Exception(Logging.Web, this, "BeginGetRequestStream", exception); 
                throw;
            } finally { 
 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream");
                if(Logging.On)Logging.Exit(Logging.Web, this, "BeginGetRequestStream", ""); 
            }
            return asyncResult;
        }
 
        public override Stream EndGetRequestStream(IAsyncResult asyncResult) {
 
            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetRequestStream", ""); 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream");
 
            Stream requestStream = null;

            try {
                // parameter validation 
                if (asyncResult==null) {
                    throw new ArgumentNullException("asyncResult"); 
                } 

                LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult; 
                if ((castedAsyncResult==null) ||
                    (HttpProxyMode?(castedAsyncResult.AsyncObject!=this.GetHttpWebRequest()):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")); 
                }
 
                if (HttpProxyMode) {
                    requestStream = GetHttpWebRequest().EndGetRequestStream(asyncResult);
                } else {
                    castedAsyncResult.InternalWaitForCompletion(); 
                    castedAsyncResult.EndCalled = true;
                    CheckError(); 
                    requestStream = m_Stream; 
                    castedAsyncResult.EndCalled = true;
                } 

                if(requestStream.CanTimeout) {
                    requestStream.WriteTimeout = ReadWriteTimeout;
                    requestStream.ReadTimeout = ReadWriteTimeout; 
                }
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "EndGetRequestStream", exception); 
                throw;
            } finally { 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream");
                if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetRequestStream", "");
            }
            return requestStream; 
        }
 
        // 
        // NOTE1: The caller must synchronize access to SubmitRequest(), only one call is even allowed for a particular request!
        // NOTE2: This method eats all exceptions so the caller must rethrow them 
        //
        private void SubmitRequest(bool async) {
            try {
                m_Async = async; 

                if (CheckCacheRetrieveBeforeSubmit()) 
                { 
                    RequestCallback(null);
                    return; 
                }

                //  This is the only place touching m_ConnectionPool
                if (m_ConnectionPool == null) 
                    m_ConnectionPool = ConnectionPoolManager.GetConnectionPool(ServicePoint, GetConnectionGroupLine(), m_CreateConnectionCallback);
 
                // 
                // FYI: Will do 2 attempts max as per AttemptedRecovery
                // 
                Stream  stream;

                while(true)
                { 
                    FtpControlStream connection = m_Connection;
 
                    if (connection == null) 
                    {
                        connection = QueueOrCreateConnection(); 
                        if (connection == null)
                            return;
                    }
 
                    if(!async){
                        if (Timeout != System.Threading.Timeout.Infinite) 
                        { 
                            m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
 
                            if(m_RemainingTimeout <= 0){
                                throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
                            }
                        } 
                    }
 
                    GlobalLog.Print("Request being submitted"+ValidationHelper.HashString(this)); 
                    connection.SetSocketTimeoutOption(SocketShutdown.Both, RemainingTimeout, false);
 
                    try {
                        stream = TimedSubmitRequestHelper(async);
                    } catch (Exception e) {
                        if (AttemptedRecovery(e)){ 
                            if(!async){
                                if (Timeout != System.Threading.Timeout.Infinite) 
                                { 
                                    m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
                                    if(m_RemainingTimeout <= 0){ 
                                        throw;
                                    }
                                }
                            } 
                            continue;
                        } 
                        throw; 
                    }
                    // no retry needed 
                    break;
                }
            } catch (WebException webException) {
                //if this was a timeout, throw a timeout exception 
                IOException ioEx = webException.InnerException as IOException;
                if(ioEx != null){ 
                    SocketException ---- = ioEx.InnerException as SocketException; 
                     if(---- != null){
                        if (----.ErrorCode == (int)SocketError.TimedOut) { 
                            SetException(new WebException(SR.GetString(SR.net_timeout), WebExceptionStatus.Timeout));
                        }
                    }
                } 

                SetException(webException); 
            } 
            catch (Exception exception) {
                SetException(exception); 
            }
        }

        // 
        //
        // 
        private FtpControlStream QueueOrCreateConnection() 
        {
            FtpControlStream connection = (FtpControlStream) m_ConnectionPool.GetConnection((object)this, (m_Async ? m_AsyncCallback : null), (m_Async ? -1: RemainingTimeout)); 

            if (connection == null)
            {
                GlobalLog.Assert(m_Async, "QueueOrCreateConnection|m_ConnectionPool.GetConnection() returned null on a [....] Request."); 
                return null;
            } 
 
            lock (m_SyncObject)
            { 
                if (m_Aborted)
                {
                    if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection)));
                    m_ConnectionPool.PutConnection(connection, this, RemainingTimeout); 
                    CheckError(); //must throw
                    throw new InternalException(); 
                } 
                m_Connection = connection;
                if (Logging.On) Logging.Associate(Logging.Web, this, m_Connection); 
            }
            return connection;
        }
        // 
        //
        private Stream TimedSubmitRequestHelper(bool async) 
        { 
            if(async) {
                // non-null in the case of re-submit (recovery) 
                if (m_RequestCompleteAsyncResult == null)
                    m_RequestCompleteAsyncResult = new LazyAsyncResult(null, null, null);
                return m_Connection.SubmitRequest(this, true, true);
            } 

            Stream stream = null; 
            bool timedOut = false; 
            TimerThread.Timer timer = TimerQueue.CreateTimer(m_TimerCallback, null);
            try { 
                stream = m_Connection.SubmitRequest(this, false, true);
            }
            catch (Exception exception) {
                if (!(exception is SocketException || exception is ObjectDisposedException) || !timer.HasExpired) { 
                    timer.Cancel();
                    throw; 
                } 

                timedOut = true; 
            }

            if (timedOut || !timer.Cancel()) {
                m_TimedOut = true; 
                throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
            } 
 
            if (stream != null)
            { 
                lock (m_SyncObject)
                {
                    if (m_Aborted)
                    { 
                        ((ICloseEx)stream).CloseEx(CloseExState.Abort|CloseExState.Silent);
                        CheckError(); //must throw 
                        throw new InternalException(); //consider replacing this on Assert 
                    }
                    m_Stream = stream; 
                }
            }

            return stream; 
        }
 
        ///  
        ///    Because this is called from the timer thread, neither it nor any methods it calls can call user code.
        ///  
        private void TimerCallback(TimerThread.Timer timer, int timeNoticed, object context) {
            GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::TimerCallback");
            FtpControlStream connection = m_Connection;
            if (connection != null) { 
                GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::TimerCallback aborting connection");
                connection.AbortConnect(); 
            } 
        }
 
        private TimerThread.Queue TimerQueue {
            get {
                if (m_TimerQueue == null) {
                    m_TimerQueue = TimerThread.GetOrCreateQueue(RemainingTimeout); 
                }
 
                return m_TimerQueue; 
            }
        } 

        /// 
        ///    Returns true if we should restart the request after an error
        ///  
        private bool AttemptedRecovery(Exception e) {
            // The first 'if' is just checking whether the exception is thrown due to the 
            // relogin failure which is a recoverable error 
            if (!(e is WebException && ((WebException)e).InternalStatus == WebExceptionInternalStatus.Isolated))
            { 
                if (e is ThreadAbortException
                    || e is StackOverflowException
                    || e is OutOfMemoryException
                    || m_OnceFailed 
                    || m_Aborted
                    || m_TimedOut 
                    || m_Connection==null 
                    || !m_Connection.RecoverableFailure)
                { 
                    return false;
                }
                m_OnceFailed = true;
            } 

            lock (m_SyncObject) { 
                if (m_ConnectionPool != null && m_Connection != null) { 
                    m_Connection.CloseSocket();
                    if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(m_Connection))); 
                    m_ConnectionPool.PutConnection(m_Connection, this, RemainingTimeout);
                    m_Connection = null;
                } else {
                    return false; 
                }
            } 
            return true; 
        }
 
        /// 
        ///    Updates and sets our exception to be thrown
        /// 
        private void SetException(Exception exception) { 

            GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SetException"); 
 
            if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
                m_Exception = exception; 
                throw exception;
            }

            FtpControlStream connection = m_Connection; 
            if (m_Exception == null) {
                if (exception is WebException) 
                { 
                    EnsureFtpWebResponse(exception);
                    m_Exception = new WebException(exception.Message, null, ((WebException)exception).Status, m_FtpWebResponse); 
                }
                else if (exception is AuthenticationException || exception is SecurityException)
                {
                    m_Exception = exception; 
                }
                else if (connection!= null && connection.StatusCode != FtpStatusCode.Undefined) 
                { 
                    EnsureFtpWebResponse(exception);
                    m_Exception = new WebException(SR.GetString(SR.net_servererror, connection.StatusLine), exception, WebExceptionStatus.ProtocolError, m_FtpWebResponse); 
                } else
                {
                    m_Exception = new WebException(exception.Message, exception);
                } 

                if (connection != null && m_FtpWebResponse != null) 
                    m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage); 
            }
        } 

        /// 
        ///    Opposite of SetException, rethrows the exception
        ///  
        private void CheckError() {
            if (m_Exception != null) { 
                throw m_Exception; 
            }
        } 

        // Return null only on [....] (if we're on the [....] thread).  Otherwise throw if no context is available.
        //
        // 

        internal override ContextAwareResult GetWritingContext() 
        { 
            if (m_ReadAsyncResult != null && m_ReadAsyncResult is ContextAwareResult)
                return (ContextAwareResult)m_ReadAsyncResult; 
            else if (m_WriteAsyncResult != null)
                return m_WriteAsyncResult;

            // [....]. 
            GlobalLog.ThreadContract(ThreadKinds.User | ThreadKinds.[....], "FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetWritingContext");
            return null; 
        } 

        // 
        //    Provides an abstract way of having Async code callback into the request (saves a delegate)
        //
        //    ATTN this method is also called on [....] path when either command or data stream gets closed
        //    Consider: Revisit the design of ftp streams 
        //
        internal override void RequestCallback(object obj) 
        { 
            if (m_Async)
                AsyncRequestCallback(obj); 
            else
                SyncRequestCallback(obj);
        }
        // 
        // Only executed for [....] requests when the pipline is completed
        // 
        private void SyncRequestCallback(object obj) 
        {
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SyncRequestCallback", "#"+ValidationHelper.HashString(obj)); 
            RequestStage stageMode = RequestStage.CheckForError;
            try {

                bool completedRequest = obj == null; 
                Exception exception = obj as Exception;
 
                GlobalLog.Print("SyncRequestCallback() exp:"+ValidationHelper.HashString(exception)+" completedRequest:"+ValidationHelper.HashString(completedRequest)); 

 
                if (exception != null)
                {
                    SetException(exception);
                } 
                else if (!completedRequest)
                { 
                    throw new InternalException(); 
                }
                else 
                {
                    // a signal on current pipeline completion
                    FtpControlStream connection = m_Connection;
 
                    bool isRevalidatedOrRetried = false;
                    if (connection != null) 
                    { 
                        EnsureFtpWebResponse(null);
 
                        // This to update response status and exit message if any
                        // Note that due to a design of FtpControlStream the status 221 "Service closing control connection" is always suppresses.
                        m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);
 
                        isRevalidatedOrRetried =!m_CacheDone &&
                                                (CacheProtocol.ProtocolStatus == CacheValidationStatus.Continue || CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer); 
 
                        // This is for [....] Upload commands that do not get chance hit GetResponse loop
                        if (m_MethodInfo.IsUpload) 
                        {
                            CheckCacheRetrieveOnResponse();
                            CheckCacheUpdateOnResponse();
                        } 
                    }
 
                    if (!isRevalidatedOrRetried) 
                        stageMode = RequestStage.ReleaseConnection;
                } 
            }
            catch (Exception exception) {
                SetException(exception);
            } 
            finally {
                FinishRequestStage(stageMode); 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SyncRequestCallback"); 
                CheckError(); //will throw on error
            } 
        }
        //
        // Only executed for Async requests
        // 
        private void AsyncRequestCallback(object obj)
        { 
            GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::AsyncRequestCallback", "#"+ValidationHelper.HashString(obj)); 
            RequestStage stageMode = RequestStage.CheckForError;
 
            try {

                FtpControlStream connection;
                connection = obj as FtpControlStream; 
                FtpDataStream stream = obj as FtpDataStream;
                Exception exception = obj as Exception; 
 
                bool completedRequest = (obj == null);
 
                GlobalLog.Print("AsyncRequestCallback()  stream:"+ValidationHelper.HashString(stream)+" conn:"+ValidationHelper.HashString(connection)+" exp:"+ValidationHelper.HashString(exception)+" completedRequest:"+ValidationHelper.HashString(completedRequest));

                while (true)
                { 
                    if (exception != null)
                    { 
                        if (AttemptedRecovery(exception)) 
                        {
                            connection = QueueOrCreateConnection(); 
                            if (connection == null)
                                return;
                            exception = null;
                        } 
                        if (exception != null)
                        { 
                            SetException(exception); 
                            break;
                        } 
                    }

                    if (connection != null)
                    { 
                        lock(m_SyncObject)
                        { 
                            if (m_Aborted) 
                            {
                                if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection))); 
                                m_ConnectionPool.PutConnection(connection, this, Timeout);
                                break;
                            }
                            m_Connection = connection; 
                            if (Logging.On) Logging.Associate(Logging.Web, this, m_Connection);
                        } 
 
                        try {
                            stream = (FtpDataStream)TimedSubmitRequestHelper(true); 
                        } catch (Exception e) {
                            exception = e;
                            continue;
                        } 
                        return;
                    } 
                    else if (stream != null) 
                    {
                        lock (m_SyncObject) 
                        {
                            if (m_Aborted)
                            {
                                ((ICloseEx)stream).CloseEx(CloseExState.Abort|CloseExState.Silent); 
                                break;
                            } 
                            m_Stream = stream; 
                        }
 
                        stream.SetSocketTimeoutOption(SocketShutdown.Both, Timeout, true);
                        EnsureFtpWebResponse(null);
                        // This one may update the Stream member on m_FtpWebResponse based on the CacheProtocol feedback.
                        CheckCacheRetrieveOnResponse(); 
                        CheckCacheUpdateOnResponse();
 
                        stageMode = stream.CanRead? RequestStage.ReadReady: RequestStage.WriteReady; 
                    }
                    else if (completedRequest) 
                    {
                        connection = m_Connection;

                        bool isRevalidatedOrRetried = false; 
                        if (connection != null)
                        { 
                            EnsureFtpWebResponse(null); 

                            // This to update response status and exit message if any 
                            // Note that due to a design of FtpControlStream the status 221 "Service closing control connection" is always suppresses.
                            m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);

                            isRevalidatedOrRetried =!m_CacheDone && 
                                                    (CacheProtocol.ProtocolStatus == CacheValidationStatus.Continue || CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer);
 
                            lock (m_SyncObject) 
                            {
                                if(!CheckCacheRetrieveOnResponse()) 
                                    continue;

                                if (m_FtpWebResponse.IsFromCache)
                                    isRevalidatedOrRetried = false; 

                                CheckCacheUpdateOnResponse(); 
                            } 
                        }
 
                        if (!isRevalidatedOrRetried)
                            stageMode = RequestStage.ReleaseConnection;
                    }
                    else 
                    {
                        throw new InternalException(); 
                    } 
                    break;
                } 
            }
            catch (Exception exception)
            {
                SetException(exception); 
            }
            finally { 
                FinishRequestStage(stageMode); 
                GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::AsyncRequestCallback");
            } 
        }

        //
        // 
        //
        private enum RequestStage { 
            CheckForError   = 0,// Do nothing except if there is an error then auto promote to ReleaseConnection 
            RequestStarted,     // Mark this request as started
            WriteReady,         // First half is done, i.e. either writer or response stream. This is always assumed unless Started or CheckForError 
            ReadReady,          // Second half is done, i.e. the read stream can be accesses.
            ReleaseConnection   // Release the control connection (request is read i.e. done-done)
        }
        // 
        // Returns a previous stage
        // 
        private RequestStage FinishRequestStage(RequestStage stage) 
        {
            GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::FinishRequestStage : stage="+stage); 
            if (m_Exception != null)
                stage = RequestStage.ReleaseConnection;

            RequestStage     prev; 
            LazyAsyncResult  writeResult;
            LazyAsyncResult  readResult; 
            FtpControlStream connection; 

            lock (m_SyncObject) 
            {
                prev = m_RequestStage;

                if (stage == RequestStage.CheckForError) 
                    return prev;
 
                if (prev == RequestStage.ReleaseConnection && 
                    stage == RequestStage.ReleaseConnection)
                { 
                    return RequestStage.ReleaseConnection;
                }

                if (stage > prev) 
                    m_RequestStage = stage;
 
                if (stage <= RequestStage.RequestStarted) 
                    return prev;
 
                writeResult  = m_WriteAsyncResult;
                readResult   = m_ReadAsyncResult;
                connection   = m_Connection;
 
                if (stage == RequestStage.ReleaseConnection)
                { 
                    if (m_Exception == null && 
                        !m_Aborted &&
                        prev != RequestStage.ReadReady && 
                        this.m_MethodInfo.IsDownload &&
                        !m_FtpWebResponse.IsFromCache)
                    {
                        return prev; 
                    }
                    if (m_Exception != null || !(m_FtpWebResponse.IsFromCache && !KeepAlive)) 
                        m_Connection = null; 
                }
            } 

            try {
                // First check to see on releasing the connection
                if ((stage == RequestStage.ReleaseConnection || 
                     prev  == RequestStage.ReleaseConnection)
                    && connection != null) 
                { 
                    try {
                        if (m_Exception != null) 
                        {
                            connection.Abort(m_Exception);
                        }
                        else if (m_FtpWebResponse.IsFromCache && !KeepAlive) 
                        {
                            // This means the response has been revalidated and found as good means the commands pipleline is completed. 
                            // Now if this request was NOT KeepAlive we want to be fair and close the control connection. 
                            // That becomes unnecessary complicated in the async case to support "QUIT" command semantic, so simply close the socket
                            // and let pool collect the object. 
                            connection.Quit();
                        }
                    } finally {
                        if (Logging.On) Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection))); 
                        m_ConnectionPool.PutConnection(connection, this, RemainingTimeout);
                        if (m_Async) 
                            if (m_RequestCompleteAsyncResult != null) 
                                m_RequestCompleteAsyncResult.InvokeCallback();
                    } 
                }
                return prev;
            }
            finally { 
                try {
                    // In any case we want to signal the writer if came here 
                    if (stage >= RequestStage.WriteReady) { 
                        // If writeResult == null and this is an upload request, it means
                        // that the user has called GetResponse() without calling 
                        // GetRequestStream() first. So they are not interested in a
                        // stream. Therefore we close the stream so that the
                        // request/pipeline can continue
                        if (m_MethodInfo.IsUpload && !m_GetRequestStreamStarted) 
                        {
                            if (m_Stream != null) 
                                m_Stream.Close(); 
                        }
                        else if (writeResult != null && !writeResult.InternalPeekCompleted) 
                            writeResult.InvokeCallback();
                    }
                }
                finally { 
                    // The response is ready either with or without a stream
                    if (stage >= RequestStage.ReadReady && readResult != null && !readResult.InternalPeekCompleted) 
                        readResult.InvokeCallback(); 
                }
            } 
        }

        //
        // Used only in the async case and only for the initial callback from the pool when connection is established. 
        //
        private static void AsyncCallbackWrapper(object request, object state) { 
            FtpWebRequest ftpWebRequest = (FtpWebRequest) request; 
            ftpWebRequest.RequestCallback(state);
        } 

        /// 
        ///    builds networkStream from Socket
        ///  
        private static PooledStream CreateFtpConnection(ConnectionPool pool) {
            return (PooledStream) new FtpControlStream(pool, TimeSpan.MaxValue, false); 
        } 

        ///  
        /// Aborts underlying connection to FTP server (command & data)
        /// 
        public override void Abort()
        { 
            if (m_Aborted)
                return; 
 
            if(Logging.On)Logging.Enter(Logging.Web, this, "Abort", "");
 
            try {

                GlobalLog.Print("FtpWebRequest#"+ValidationHelper.HashString(this)+"::Abort()");
 
                if (HttpProxyMode) {
                    GetHttpWebRequest().Abort(); 
                    return; 
                }
 
                if (CacheProtocol != null)
                    CacheProtocol.Abort();

                Stream stream; 
                FtpControlStream connection;
                lock (m_SyncObject) 
                { 
                    if (m_RequestStage >= RequestStage.ReleaseConnection)
                        return; 
                    m_Aborted = true;
                    stream  = m_Stream;
                    connection = m_Connection;
                    m_Exception =  new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), 
                                                    WebExceptionStatus.RequestCanceled) ;
                } 
 
                if (stream != null)
                { 
                    GlobalLog.Assert(stream is ICloseEx, "FtpWebRequest.Abort()|The m_Stream member is not CloseEx hence the risk of connection been orphaned.");
                    ((ICloseEx)stream).CloseEx(CloseExState.Abort|CloseExState.Silent);
                }
                if (connection != null) 
                    connection.Abort(ExceptionHelper.RequestAbortedException);
 
            } catch (Exception exception) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "Abort", exception);
                throw; 
            } finally {
                if(Logging.On)Logging.Exit(Logging.Web, this, "Abort", "");
            }
        } 

        ///  
        ///  
        /// 
        /// If KeepAlive is set to false, then the control connection to the server will be closed when the request completes. 
        /// Default is true
        /// 
        /// 
        public bool KeepAlive { 
            get {
                return m_KeepAlive; 
            } 
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                }
                m_KeepAlive = value;
            } 
        }
 
        ///  
        /// True by default, false allows transmission using text mode
        ///  
        public bool UseBinary {
            get {
                return m_Binary;
            } 
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                }
                m_Binary = value; 
            }
        }

        ///  
        /// False by default, true enables passive mode communication with server.
        /// This alters the way the client talks with the server, allowing the client 
        /// to initiate the data connection with the server 
        /// 
        public bool UsePassive { 
            get {
                return m_Passive;
            }
            set { 
                if (InUse) {
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted)); 
                } 
                m_Passive = 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 (m_ClientCertificates == null) {
                    lock (m_SyncObject) { 
                        if (m_ClientCertificates == null) { 
                            m_ClientCertificates = new X509CertificateCollection();
                        } 
                    }
                }
                return m_ClientCertificates;
            } 
            set {
                if (value==null) { 
                    throw new ArgumentNullException("value"); 
                }
                m_ClientCertificates = value; 
            }
        }
#endif // !FEATURE_PAL
 
        /// 
        ///    Set to true if we need SSL 
        ///  
        public bool EnableSsl {
            get { 
                return m_EnableSsl;
            }
            set {
                if (InUse) { 
                    throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                } 
                m_EnableSsl = value; 
            }
        } 


        /// 
        ///     
        ///       A collection of headers, currently nothing is return except an empty collection
        ///     
        ///  
        public override WebHeaderCollection Headers {
            get { 
                if (HttpProxyMode) {
                    return GetHttpWebRequest().Headers;
                }
                if (m_FtpRequestHeaders == null) { 
                    m_FtpRequestHeaders         = new WebHeaderCollection(WebHeaderCollectionType.FtpWebRequest);
                } 
                return m_FtpRequestHeaders; 
            }
            set { 
                if (HttpProxyMode) {
                    GetHttpWebRequest().Headers = value;
                }
                m_FtpRequestHeaders = value; 
            }
        } 
 
        // NOT SUPPORTED method
        public override string ContentType { 
            get {
                throw ExceptionHelper.PropertyNotSupportedException;
            }
            set { 
                throw ExceptionHelper.PropertyNotSupportedException;
            } 
        } 

        // NOT SUPPORTED method 
        public override bool UseDefaultCredentials  {
            get {
                throw ExceptionHelper.PropertyNotSupportedException;
            } 
            set {
                throw ExceptionHelper.PropertyNotSupportedException; 
            } 
        }
 
        // NOT SUPPORTED method
        public override bool PreAuthenticate {
            get {
                throw ExceptionHelper.PropertyNotSupportedException; 
            }
            set { 
                throw ExceptionHelper.PropertyNotSupportedException; 
            }
        } 

        /// 
        ///    True if a request has been submitted (ie already active)
        ///  
        private bool InUse {
            get { 
                if (m_GetRequestStreamStarted || m_GetResponseStarted) { 
                    return true;
                } else { 
                    return false;
                }
            }
        } 

        ///  
        ///    True if request is just wrapping HttpWebRequest 
        /// 
        private bool HttpProxyMode { 
            get {
                return (m_HttpWebRequest != null);
            }
        } 

 
        ///  
        ///    Creates an FTP WebResponse based off the responseStream and our active Connection
        ///  
        private void EnsureFtpWebResponse(Exception exception)
        {
            if (m_FtpWebResponse == null || (m_FtpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && m_Stream != null))
            { 
                lock (m_SyncObject) {
                    if (m_FtpWebResponse == null || (m_FtpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && m_Stream != null)) 
                    { 
                        Stream responseStream = m_Stream;
 
                        if (m_MethodInfo.IsUpload) {
                            responseStream = null;
                        }
 
                        if(m_Stream != null && m_Stream.CanRead && m_Stream.CanTimeout)
                        { 
                            m_Stream.ReadTimeout = ReadWriteTimeout; 
                            m_Stream.WriteTimeout = ReadWriteTimeout;
                        } 

                        FtpControlStream connection = m_Connection;
                        long contentLength = connection != null? connection.ContentLength: -1;
 
                        if (responseStream == null)
                        { 
 
                            // If the last command was SIZE, we set the ContentLength on
                            // the FtpControlStream to be the size of the file returned in the 
                            // response. We should propagate that file size to the response so
                            // users can access it. This also maintains the compatibility with
                            // HTTP when returning size instead of content.
                            if (contentLength < 0) 
                                contentLength = 0;
                        } 
 
                        if (m_FtpWebResponse != null)
                        { 
                            m_FtpWebResponse.SetResponseStream(responseStream);
                        }
                        else
                        { 
                            if (connection != null)
                                m_FtpWebResponse = new FtpWebResponse(responseStream, contentLength, connection.ResponseUri, connection.StatusCode, connection.StatusLine, connection.LastModified, connection.BannerMessage, connection.WelcomeMessage, connection.ExitMessage); 
                            else 
                                m_FtpWebResponse = new FtpWebResponse(responseStream, -1, m_Uri, FtpStatusCode.Undefined, null, DateTime.Now, null, null, null);
                        } 
                    }
                }
            }
 
            GlobalLog.Print("FtpWebRequest#"+ValidationHelper.HashString(this)+"::EnsureFtpWebResponse returns #"+ValidationHelper.HashString(m_FtpWebResponse)+" with stream#"+ValidationHelper.HashString(m_FtpWebResponse.m_ResponseStream));
            return; 
        } 

        ///  
        ///    Creates a HttpWebRequest
        /// 
        private HttpWebRequest GetHttpWebRequest() {
            lock (m_SyncObject) { 
                if (m_HttpWebRequest == null) {
                    if (m_ContentOffset > 0) { 
                        throw new InvalidOperationException(SR.GetString(SR.net_ftp_no_offsetforhttp)); 
                    }
 
                    if (!m_MethodInfo.HasHttpCommand)
                        throw new InvalidOperationException(SR.GetString(SR.net_ftp_no_http_cmd));

                    m_HttpWebRequest = new HttpWebRequest(m_Uri, ServicePoint); 
                    m_HttpWebRequest.Credentials = Credentials;
                    m_HttpWebRequest.InternalProxy = m_Proxy; 
                    m_HttpWebRequest.KeepAlive = KeepAlive; 
                    m_HttpWebRequest.Timeout = Timeout;
                    m_HttpWebRequest.Method = m_MethodInfo.HttpCommand; 
                    m_HttpWebRequest.CacheProtocol = CacheProtocol;
                    RequestCacheLevel effectiveLevel;
                    if (CachePolicy == null)
                        effectiveLevel = RequestCacheLevel.BypassCache; 
                    else
                        effectiveLevel = CachePolicy.Level; 
 
                    // Cannot support revalidate through the proxy
                    if (effectiveLevel == RequestCacheLevel.Revalidate) 
                        effectiveLevel = RequestCacheLevel.Reload;
                    m_HttpWebRequest.CachePolicy = new HttpRequestCachePolicy((HttpRequestCacheLevel)effectiveLevel);

                    //disable cache protocol on that class since we are proxying through HTTP 
                    CacheProtocol = null;
 
                } 
            }
            return m_HttpWebRequest; 
        }


        ///  
        ///    Generates a string that
        ///     allows a Connection to remain unique for user 
        ///     this is needed to prevent multiple users from 
        ///     using the same sockets after they mess with things
        ///  
        private string GetConnectionGroupLine() {
            GlobalLog.Print("GetConnectionGroupLine");
            return ConnectionGroupName + "_" + GetUserString();
        } 

 
        ///  
        ///    Returns username string
        ///  
        internal string GetUserString() {
            string name = null;
            if (this.Credentials != null) {
                NetworkCredential networkCreds = this.Credentials.GetCredential(m_Uri, "basic"); 
                if (networkCreds != null) {
                    name = networkCreds.InternalGetUserName(); 
                    string domain = networkCreds.InternalGetDomain(); 
                    if (!ValidationHelper.IsBlankString(domain)) {
                        name = domain+"\\"+name; 
                    }
                }
            }
            return name == null? null: (String.Compare(name,"anonymous", StringComparison.InvariantCultureIgnoreCase) == 0? null: name); 
        }
 
        // 
        // This method may be invoked as part of the request submission but
        // before the response is received 
        // Return:
        // - True       = Use CacheProtocol properties to create the cached response
        // - False      = Proceed with the request submission
        private bool CheckCacheRetrieveBeforeSubmit() { 

            if (CacheProtocol == null || m_CacheDone) { 
                m_CacheDone = true; 
                return false;
            } 

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse ||
                CacheProtocol.ProtocolStatus == CacheValidationStatus.DoNotTakeFromCache)
            { 
                // Re-entry into a new pipeline on failed revalidate or combining cached and live streams
                return false; 
            } 

            Uri cacheUri = RequestUri; 
            string username = GetUserString();
            if(username != null)
                username = Uri.EscapeDataString(username);
 
            if (cacheUri.Fragment.Length != 0 || username != null)
            { 
                if (username == null) 
                    cacheUri = new Uri(cacheUri.GetParts(UriComponents.AbsoluteUri & ~(UriComponents.Fragment|UriComponents.UserInfo), UriFormat.SafeUnescaped));
                else 
                {
                    username =  cacheUri.GetParts((UriComponents.Scheme | UriComponents.KeepDelimiter), UriFormat.SafeUnescaped) + username + '@';
                    username += cacheUri.GetParts((UriComponents.Host | UriComponents.Port | UriComponents.Path | UriComponents.Query), UriFormat.SafeUnescaped);
                    cacheUri = new Uri(username); 
                }
            } 
 
            CacheProtocol.GetRetrieveStatus(cacheUri, this);
 
            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) {
                throw CacheProtocol.ProtocolException;
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) {
                return false; 
            } 

            if (m_MethodInfo.Operation != FtpOperation.DownloadFile) { 
                throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_command));
            }

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.ReturnCachedResponse) 
            {
                // If we take it from cache, we have to kick in response processing 
                // The _CacheStream is good to return as the response stream. 
                FtpRequestCacheValidator ctx = (FtpRequestCacheValidator) CacheProtocol.Validator;
                m_FtpWebResponse = new FtpWebResponse(CacheProtocol.ResponseStream, 
                                                      CacheProtocol.ResponseStreamLength,
                                                      RequestUri,
                                                      UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData,
                                                      (UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData).ToString(), 
                                                      ctx.CacheEntry.LastModifiedUtc == DateTime.MinValue? DateTime.Now: ctx.CacheEntry.LastModifiedUtc.ToLocalTime(),
                                                      string.Empty, 
                                                      string.Empty, 
                                                      string.Empty);
 
                m_FtpWebResponse.InternalSetFromCache = true;
                m_FtpWebResponse.InternalSetIsCacheFresh = (ctx.CacheFreshnessStatus != CacheFreshnessStatus.Stale);
            }
            return true; 
        }
 
        // 
        // 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() { 

            if (CacheProtocol == null || m_CacheDone) { 
                return true; 
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.Continue)
            {
                // cache has been already revalidated proceed with cache update
                return true; 
            }
 
            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) { 
                if(Logging.On)Logging.Exception(Logging.Web, this, "CheckCacheRetrieveOnResponse", CacheProtocol.ProtocolException);
                throw CacheProtocol.ProtocolException; 
            }

            // At this point we dont have the real data stream, hence passing null and updating it later
            CacheProtocol.GetRevalidateStatus(m_FtpWebResponse, null); 

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer) 
            { 
                if (m_FtpWebResponse != null)
                    m_FtpWebResponse.SetResponseStream(null); //prevent from advancing commands pipeline 
                // Try to resubmit or fail
                return false;
            }
 
            if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse)
            { 
                // Proceed with the requesting the real server data stream 
                return false;
            } 

            if (m_MethodInfo.Operation != FtpOperation.DownloadFile)
            {
                // This should never happen in real life 
                throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_command));
            } 
 

            FtpRequestCacheValidator ctx = (FtpRequestCacheValidator) CacheProtocol.Validator; 

            FtpWebResponse oldResponse = m_FtpWebResponse;
            m_Stream = CacheProtocol.ResponseStream;
            m_FtpWebResponse = new FtpWebResponse(CacheProtocol.ResponseStream, 
                                                  CacheProtocol.ResponseStreamLength,
                                                  RequestUri, 
                                                  UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData, 
                                                  (UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData).ToString(),
                                                  ctx.CacheEntry.LastModifiedUtc == DateTime.MinValue? DateTime.Now: ctx.CacheEntry.LastModifiedUtc.ToLocalTime(), 
                                                  string.Empty,
                                                  string.Empty,
                                                  string.Empty);
 
            m_FtpWebResponse.InternalSetFromCache = true;
            m_FtpWebResponse.InternalSetIsCacheFresh = CacheProtocol.IsCacheFresh; 
 
            oldResponse.Close();
            return true; 
        }


 
        //
        // This will decide on cache update and construct the effective response stream 
        // 
        private void CheckCacheUpdateOnResponse()
        { 
            if (CacheProtocol == null || m_CacheDone) {
                return;
            }
            m_CacheDone = true; 

            if (m_Connection != null) 
            { 
                m_FtpWebResponse.UpdateStatus(m_Connection.StatusCode, m_Connection.StatusLine, m_Connection.ExitMessage);
                if (m_Connection.StatusCode == FtpStatusCode.OpeningData && m_FtpWebResponse.ContentLength == 0) 
                    m_FtpWebResponse.SetContentLength(m_Connection.ContentLength);
            }

            if (CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse) 
            {
                // Note we already asked for a file restart 
                // The only problem is that we could not create the combined stream sooner. 
                m_Stream = new CombinedReadStream(CacheProtocol.Validator.CacheStream, m_FtpWebResponse.GetResponseStream());
                // 
                // For consistent user experience we always supply DataAlreadyOpen status for a cached response.
                //
                FtpStatusCode rightStatus = UsePassive? FtpStatusCode.DataAlreadyOpen: FtpStatusCode.OpeningData;
 
                m_FtpWebResponse.UpdateStatus(rightStatus, rightStatus.ToString(), string.Empty);
                m_FtpWebResponse.SetResponseStream(m_Stream); 
            } 

            if (CacheProtocol.GetUpdateStatus(m_FtpWebResponse, m_FtpWebResponse.GetResponseStream()) == CacheValidationStatus.UpdateResponseInformation) 
            {
                m_Stream = CacheProtocol.ResponseStream;
                m_FtpWebResponse.SetResponseStream(m_Stream);
            } 
            else if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail)
                throw CacheProtocol.ProtocolException; 
        } 

        internal void DataStreamClosed(CloseExState closeState) 
        {
            if ((closeState & CloseExState.Abort) == 0)
            {
                if (!m_Async) 
                {
                    if (m_Connection != null) 
                        m_Connection.CheckContinuePipeline(); 
                }
                else 
                {
                    m_RequestCompleteAsyncResult.InternalWaitForCompletion();
                    CheckError();
                } 
            }
            else 
            { 
                FtpControlStream connection = m_Connection;
                if (connection != null) 
                    connection.Abort(ExceptionHelper.RequestAbortedException);
            }
        }
    }  // class FtpWebRequest 

    // 
    // Class used by the WebRequest.Create factory to create FTP requests 
    //
    internal class FtpWebRequestCreator : IWebRequestCreate { 
        internal FtpWebRequestCreator() {
        }
        public WebRequest Create(Uri uri) {
            return new FtpWebRequest(uri); 
        }
    } // class FtpWebRequestCreator 
 
} //namespace System.Net
 



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

                        

Link Menu

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