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

  1. // ------------------------------------------------------------------------------
  2. // <copyright file="FtpWebRequest.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // ------------------------------------------------------------------------------
  15. //
  16. namespace System.Net
  17. {
  18.     using System.Collections;
  19.     using System.IO;
  20.     using System.Text;
  21.     using System.Net.Sockets;
  22.     using System.Net.Cache;
  23.     using System.Threading;
  24.     using System.Security;
  25.     using System.Security.Cryptography.X509Certificates;
  26.     using System.Security.Permissions;
  27.     using System.Globalization;
  28.    
  29.    
  30.     /// <summary>
  31.     /// <para>Allows us to control what the request is used for (based on the type of behavior,
  32.     /// that the command calls for)</para>
  33.     /// </summary>
  34.     internal enum FtpOperation
  35.     {
  36.         DownloadFile = 0,
  37.         ListDirectory = 1,
  38.         ListDirectoryDetails = 2,
  39.         UploadFile = 3,
  40.         UploadFileUnique = 4,
  41.         AppendFile = 5,
  42.         DeleteFile = 6,
  43.         GetDateTimestamp = 7,
  44.         GetFileSize = 8,
  45.         Rename = 9,
  46.         MakeDirectory = 10,
  47.         RemoveDirectory = 11,
  48.         PrintWorkingDirectory = 12,
  49.         Other = 13
  50.     }
  51.    
  52.     [Flags()]
  53.     internal enum FtpMethodFlags
  54.     {
  55.         None = 0,
  56.         IsDownload = 1,
  57.         IsUpload = 2,
  58.         TakesParameter = 4,
  59.         MayTakeParameter = 8,
  60.         DoesNotTakeParameter = 16,
  61.         ParameterIsDirectory = 32,
  62.         ShouldParseForResponseUri = 64,
  63.         HasHttpCommand = 128
  64.     }
  65.    
  66.     internal class FtpMethodInfo
  67.     {
  68.         internal string Method;
  69.         internal FtpOperation Operation;
  70.         internal FtpMethodFlags Flags;
  71.         internal string HttpCommand;
  72.        
  73.         internal FtpMethodInfo(string method, FtpOperation operation, FtpMethodFlags flags, string httpCommand)
  74.         {
  75.             Method = method;
  76.             Operation = operation;
  77.             Flags = flags;
  78.             HttpCommand = httpCommand;
  79.         }
  80.        
  81.         internal bool HasFlag(FtpMethodFlags flags)
  82.         {
  83.             return (Flags & flags) != 0;
  84.         }
  85.        
  86.         internal bool IsCommandOnly {
  87.             get { return (Flags & (FtpMethodFlags.IsDownload | FtpMethodFlags.IsUpload)) == 0; }
  88.         }
  89.        
  90.         internal bool IsUpload {
  91.             get { return (Flags & FtpMethodFlags.IsUpload) != 0; }
  92.         }
  93.        
  94.         internal bool IsDownload {
  95.             get { return (Flags & FtpMethodFlags.IsDownload) != 0; }
  96.         }
  97.        
  98.         internal bool HasHttpCommand {
  99.             get { return (Flags & FtpMethodFlags.HasHttpCommand) != 0; }
  100.         }
  101.        
  102.         /// <summary>
  103.         /// <para>True if we should attempt to get a response uri
  104.         /// out of a server response</para>
  105.         /// </summary>
  106.         internal bool ShouldParseForResponseUri {
  107.             get { return (Flags & FtpMethodFlags.ShouldParseForResponseUri) != 0; }
  108.         }
  109.        
  110.         /// <summary>
  111.         /// <para>Indicates that the user gave us an unknown method
  112.         /// (something not in FtpMethods)</para>
  113.         /// </summary>
  114.         internal bool IsUnknownMethod {
  115.             get { return (Operation == FtpOperation.Other); }
  116.         }
  117.        
  118.         static internal FtpMethodInfo GetMethodInfo(string method)
  119.         {
  120.             method = method.ToUpper(CultureInfo.InvariantCulture);
  121.             foreach (FtpMethodInfo methodInfo in KnownMethodInfo)
  122.                 if (method == methodInfo.Method)
  123.                     return methodInfo;
  124.             // Currently we don't support generic methods. If we want to support it
  125.             // just remove this line and uncomment the next commented block
  126.             throw new ArgumentException(SR.GetString(SR.net_ftp_unsupported_method), "method");
  127.             /*
  128.             return (new FtpMethodInfo(method,
  129.                                       FtpOperation.Other,
  130.                                       FtpMethodFlags.None,
  131.                                       null));
  132.             */           
  133.         }
  134.        
  135.         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.HasHttpCommand | FtpMethodFlags.MayTakeParameter, "GET"), new FtpMethodInfo(WebRequestMethods.Ftp.ListDirectoryDetails, FtpOperation.ListDirectoryDetails, FtpMethodFlags.IsDownload | 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.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),
  136.         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)};
  137.        
  138.     }
  139.    
  140.     /// <summary>
  141.     /// <para>The FtpWebRequest class implements a basic FTP client
  142.     /// interface.</para>
  143.     /// </summary>
  144.     public sealed class FtpWebRequest : WebRequest
  145.     {
  146.         private object m_SyncObject;
  147.         private ICredentials m_AuthInfo;
  148.         private readonly Uri m_Uri;
  149.         private FtpMethodInfo m_MethodInfo;
  150.         private string m_RenameTo = null;
  151.         private bool m_GetRequestStreamStarted;
  152.         private bool m_GetResponseStarted;
  153.         private DateTime m_StartTime;
  154.         private int m_Timeout = s_DefaultTimeout;
  155.         private int m_RemainingTimeout;
  156.         private long m_ContentLength = 0;
  157.         private long m_ContentOffset = 0;
  158.         private IWebProxy m_Proxy;
  159.         private bool m_KeepAlive = true;
  160.         private bool m_Passive = true;
  161.         private bool m_Binary = true;
  162.         private string m_ConnectionGroupName;
  163.         private ServicePoint m_ServicePoint;
  164.        
  165.         private bool m_CacheDone;
  166.         // Not sure why but the command stream wants to notify the request on every pipiline closure closure by invoking RequestCallback.
  167.         // m_CacheDone is to facilitate PutConnection decision and to prevent bothering cache protocol when it's all completed.
  168.         private bool m_Async;
  169.         private bool m_Aborted;
  170.         private bool m_TimedOut;
  171.        
  172.         private HttpWebRequest m_HttpWebRequest;
  173.         private Exception m_Exception;
  174.        
  175.         private TimerThread.Queue m_TimerQueue = s_DefaultTimerQueue;
  176.         private TimerThread.Callback m_TimerCallback;
  177.        
  178.         private bool m_EnableSsl;
  179.         private bool m_ProxyUserSet;
  180.         private ConnectionPool m_ConnectionPool;
  181.         private FtpControlStream m_Connection;
  182.         private Stream m_Stream;
  183.         private RequestStage m_RequestStage;
  184.         private bool m_OnceFailed;
  185.         private WebHeaderCollection m_FtpRequestHeaders;
  186.         private FtpWebResponse m_FtpWebResponse;
  187.         private int m_ReadWriteTimeout = 5 * 60 * 1000;
  188.         //5 minutes.
  189.        
  190.         private ContextAwareResult m_WriteAsyncResult;
  191.         private LazyAsyncResult m_ReadAsyncResult;
  192.         private LazyAsyncResult m_RequestCompleteAsyncResult;
  193.        
  194.         private static readonly GeneralAsyncDelegate m_AsyncCallback = new GeneralAsyncDelegate(AsyncCallbackWrapper);
  195.         private static readonly CreateConnectionDelegate m_CreateConnectionCallback = new CreateConnectionDelegate(CreateFtpConnection);
  196.         private static readonly NetworkCredential DefaultFtpNetworkCredential = new NetworkCredential("anonymous", "anonymous@", String.Empty, false);
  197.         private static readonly int s_DefaultTimeout = WebRequest.DefaultTimeout;
  198.         private static readonly TimerThread.Queue s_DefaultTimerQueue = TimerThread.GetOrCreateQueue(s_DefaultTimeout);
  199.        
  200.         // Used by FtpControlStream
  201.         internal FtpMethodInfo MethodInfo {
  202.             get { return m_MethodInfo; }
  203.         }
  204.        
  205.         // Used by FtpControlStream
  206.         static internal NetworkCredential DefaultNetworkCredential {
  207.             get { return DefaultFtpNetworkCredential; }
  208.         }
  209.        
  210.         // This is a shortcut that would set the default policy for HTTP/HTTPS.
  211.         // The default policy is overridden by any prefix-registered policy.
  212.         // Will demand permission for set{}
  213.         public static new RequestCachePolicy DefaultCachePolicy {
  214.             get {
  215.                 RequestCachePolicy policy = RequestCacheManager.GetBinding(Uri.UriSchemeFtp).Policy;
  216.                 if (policy == null)
  217.                     return WebRequest.DefaultCachePolicy;
  218.                 return policy;
  219.             }
  220.             set {
  221.                 // This is a replacement of RequestCachePermission demand since we are not including the latest in the product.
  222.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  223.                
  224.                 RequestCacheBinding binding = RequestCacheManager.GetBinding(Uri.UriSchemeFtp);
  225.                 RequestCacheManager.SetBinding(Uri.UriSchemeFtp, new RequestCacheBinding(binding.Cache, binding.Validator, value));
  226.             }
  227.         }
  228.        
  229.         /// <summary>
  230.         /// <para>
  231.         /// Selects upload or download of files. WebRequestMethods.Ftp.DownloadFile is default.
  232.         /// Not allowed to be changed once request is started.
  233.         /// </para>
  234.         /// </summary>
  235.         public override string Method {
  236.             get { return m_MethodInfo.Method; }
  237.             set {
  238.                 if (String.IsNullOrEmpty(value)) {
  239.                     throw new ArgumentException(SR.GetString(SR.net_ftp_invalid_method_name), "value");
  240.                 }
  241.                 if (InUse) {
  242.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  243.                 }
  244.                 try {
  245.                     m_MethodInfo = FtpMethodInfo.GetMethodInfo(value);
  246.                 }
  247.                 catch (ArgumentException) {
  248.                     throw new ArgumentException(SR.GetString(SR.net_ftp_unsupported_method), "value");
  249.                 }
  250.             }
  251.         }
  252.        
  253.         /// <summary>
  254.         /// <para>
  255.         /// Sets the target name for the WebRequestMethods.Ftp.Rename command
  256.         /// Not allowed to be changed once request is started.
  257.         /// </para>
  258.         /// </summary>
  259.         public string RenameTo {
  260.             get { return m_RenameTo; }
  261.             set {
  262.                 if (InUse) {
  263.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  264.                 }
  265.                
  266.                 if (String.IsNullOrEmpty(value)) {
  267.                     throw new ArgumentException(SR.GetString(SR.net_ftp_invalid_renameto), "value");
  268.                 }
  269.                
  270.                 m_RenameTo = value;
  271.             }
  272.         }
  273.        
  274.         /// <summary>
  275.         /// <para>Used for clear text authentication with FTP server</para>
  276.         /// </summary>
  277.         public override ICredentials Credentials {
  278.             get { return m_AuthInfo; }
  279.             set {
  280.                 if (InUse) {
  281.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  282.                 }
  283.                 if (value == null) {
  284.                     throw new ArgumentNullException("value");
  285.                 }
  286.                 if (value is SystemNetworkCredential) {
  287.                     throw new ArgumentException(SR.GetString(SR.net_ftp_no_defaultcreds), "value");
  288.                 }
  289.                 m_AuthInfo = value;
  290.             }
  291.         }
  292.        
  293.         /// <summary>
  294.         /// <para>Gets the Uri used to make the request</para>
  295.         /// </summary>
  296.         public override Uri RequestUri {
  297.             get { return m_Uri; }
  298.         }
  299.        
  300.         /// <summary>
  301.         /// <para>Timeout of the blocking calls such as GetResponse and GetRequestStream (default 100 secs)</para>
  302.         /// </summary>
  303.         public override int Timeout {
  304.             get { return m_Timeout; }
  305.             set {
  306.                 if (InUse) {
  307.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  308.                 }
  309.                 if (value < 0 && value != System.Threading.Timeout.Infinite) {
  310.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_io_timeout_use_ge_zero));
  311.                 }
  312.                 if (m_Timeout != value) {
  313.                     m_Timeout = value;
  314.                     m_TimerQueue = null;
  315.                 }
  316.             }
  317.         }
  318.        
  319.         // This can always be calculaed as Remaining = Timeout - (Now - Start)
  320.         // but we are keeping this for performance reasons (To avoid unnecessary
  321.         // calculations). This can be removed if the performance gains are
  322.         // considered negligible and not necessary
  323.         internal int RemainingTimeout {
  324.             get { return m_RemainingTimeout; }
  325.         }
  326.        
  327.        
  328.        
  329.         /// <devdoc>
  330.         /// <para>Used to control the Timeout when calling Stream.Read (AND) Stream.Write.
  331.         /// Effects Streams returned from GetResponse().GetResponseStream() (AND) GetRequestStream().
  332.         /// Default is 5 mins.
  333.         /// </para>
  334.         /// </devdoc>
  335.         public int ReadWriteTimeout {
  336.             get { return m_ReadWriteTimeout; }
  337.             set {
  338.                 if (m_GetResponseStarted) {
  339.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  340.                 }
  341.                 if (value <= 0 && value != System.Threading.Timeout.Infinite) {
  342.                     throw new ArgumentOutOfRangeException(SR.GetString(SR.net_io_timeout_use_gt_zero));
  343.                 }
  344.                 m_ReadWriteTimeout = value;
  345.             }
  346.         }
  347.        
  348.         /// <summary>
  349.         /// <para>Used to specify what offset we will read at</para>
  350.         /// </summary>
  351.         public long ContentOffset {
  352.             get { return m_ContentOffset; }
  353.             set {
  354.                 if (InUse) {
  355.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  356.                 }
  357.                 if (value < 0) {
  358.                     throw new ArgumentOutOfRangeException("value");
  359.                 }
  360.                 m_ContentOffset = value;
  361.             }
  362.         }
  363.        
  364.        
  365.        
  366.         /// <summary>
  367.         /// <para>Gets or sets the data size of to-be uploaded data</para>
  368.         /// </summary>
  369.         public override long ContentLength {
  370.             get { return m_ContentLength; }
  371.             set { m_ContentLength = value; }
  372.         }
  373.        
  374.         /// <summary>
  375.         /// <para>Uses an HTTP proxy if needed to send FTP request</para>
  376.         /// </summary>
  377.         public override IWebProxy Proxy {
  378.             get {
  379.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  380.                 return m_Proxy;
  381.             }
  382.             set {
  383.                 ExceptionHelper.WebPermissionUnrestricted.Demand();
  384.                 if (InUse) {
  385.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  386.                 }
  387.                 m_ProxyUserSet = true;
  388.                 m_Proxy = value;
  389.                 m_ServicePoint = null;
  390.                 ServicePoint refreshIt = ServicePoint;
  391.             }
  392.         }
  393.        
  394.         /// <devdoc>
  395.         /// <para>Allows private ConnectionPool(s) to be used</para>
  396.         /// </devdoc>
  397.         public override string ConnectionGroupName {
  398.             get { return m_ConnectionGroupName; }
  399.             set {
  400.                 if (InUse) {
  401.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  402.                 }
  403.                 m_ConnectionGroupName = value;
  404.             }
  405.         }
  406.        
  407.         /// <devdoc>
  408.         /// <para>Generates a service point for this request, and allows setting of Connection settings</para>
  409.         /// </devdoc>
  410.         public ServicePoint ServicePoint {
  411.             get {
  412.                 if (m_ServicePoint == null) {
  413.                     IWebProxy proxy = m_Proxy;
  414.                     if (!m_ProxyUserSet)
  415.                         proxy = WebRequest.InternalDefaultWebProxy;
  416.                    
  417.                     ServicePoint servicePoint = ServicePointManager.FindServicePoint(m_Uri, proxy);
  418.                    
  419.                     lock (m_SyncObject) {
  420.                         if (m_ServicePoint == null) {
  421.                             m_ServicePoint = servicePoint;
  422.                             m_Proxy = proxy;
  423.                         }
  424.                     }
  425.                 }
  426.                 return m_ServicePoint;
  427.             }
  428.         }
  429.        
  430.         internal bool Aborted {
  431.             get { return m_Aborted; }
  432.         }
  433.        
  434.         /// <summary>
  435.         /// <para>
  436.         /// Initializes a new instance of the <see cref='System.Net.FtpWebRequest'/>
  437.         /// class.
  438.         /// </para>
  439.         /// </summary>
  440.         internal FtpWebRequest(Uri uri)
  441.         {
  442.             (new WebPermission(NetworkAccess.Connect, uri)).Demand();
  443.            
  444.             if (Logging.On)
  445.                 Logging.PrintInfo(Logging.Web, this, ".ctor", uri.ToString());
  446.            
  447.             if ((object)uri.Scheme != (object)Uri.UriSchemeFtp)
  448.                 throw new ArgumentOutOfRangeException("uri");
  449.            
  450.             m_TimerCallback = new TimerThread.Callback(TimerCallback);
  451.             m_SyncObject = new object();
  452.            
  453.             NetworkCredential networkCredential = null;
  454.             m_Uri = uri;
  455.             m_MethodInfo = FtpMethodInfo.GetMethodInfo(WebRequestMethods.Ftp.DownloadFile);
  456.             if (m_Uri.UserInfo != null && m_Uri.UserInfo.Length != 0) {
  457.                 string userInfo = m_Uri.UserInfo;
  458.                 string username = userInfo;
  459.                 string password = "";
  460.                 int index = userInfo.IndexOf(':');
  461.                 if (index != -1) {
  462.                     username = Uri.UnescapeDataString(userInfo.Substring(0, index));
  463.                     index++;
  464.                     // skip ':'
  465.                     password = Uri.UnescapeDataString(userInfo.Substring(index, userInfo.Length - index));
  466.                 }
  467.                 networkCredential = new NetworkCredential(username, password);
  468.             }
  469.             if (networkCredential == null) {
  470.                 networkCredential = DefaultFtpNetworkCredential;
  471.             }
  472.             m_AuthInfo = networkCredential;
  473.             SetupCacheProtocol(m_Uri);
  474.         }
  475.        
  476.        
  477.         //
  478.         // Used to query for the Response of an FTP request
  479.         //
  480.         public override WebResponse GetResponse()
  481.         {
  482.             if (Logging.On)
  483.                 Logging.Enter(Logging.Web, this, "GetResponse", "");
  484.             if (Logging.On)
  485.                 Logging.PrintInfo(Logging.Web, this, "GetResponse", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method));
  486.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse");
  487.            
  488.             try {
  489.                 CheckError();
  490.                
  491.                 if (m_FtpWebResponse != null)
  492.                     return m_FtpWebResponse;
  493.                
  494.                 if (m_GetResponseStarted) {
  495.                     throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  496.                 }
  497.                
  498.                 m_GetResponseStarted = true;
  499.                
  500.                 m_StartTime = DateTime.UtcNow;
  501.                 m_RemainingTimeout = Timeout;
  502.                
  503.                 // We don't really need this variable, but we just need
  504.                 // to call the property to measure its execution time
  505.                 ServicePoint servicePoint = ServicePoint;
  506.                
  507.                 if (Timeout != System.Threading.Timeout.Infinite) {
  508.                     m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
  509.                    
  510.                     if (m_RemainingTimeout <= 0) {
  511.                         throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
  512.                     }
  513.                 }
  514.                
  515.                 if (ServicePoint.InternalProxyServicePoint) {
  516.                     if (EnableSsl) {
  517.                         m_GetResponseStarted = false;
  518.                         throw new WebException(SR.GetString(SR.net_ftp_proxy_does_not_support_ssl));
  519.                     }
  520.                    
  521.                     try {
  522.                         HttpWebRequest httpWebRequest = GetHttpWebRequest();
  523.                         if (Logging.On)
  524.                             Logging.Associate(Logging.Web, this, httpWebRequest);
  525.                        
  526.                         m_FtpWebResponse = new FtpWebResponse((HttpWebResponse)httpWebRequest.GetResponse());
  527.                     }
  528.                     catch (WebException webException) {
  529.                         if (webException.Response != null && webException.Response is HttpWebResponse) {
  530.                             webException = new WebException(webException.Message, null, webException.Status, new FtpWebResponse((HttpWebResponse)webException.Response), webException.InternalStatus);
  531.                         }
  532.                         SetException(webException);
  533.                         throw webException;
  534.                     }
  535.                 }
  536.                 else {
  537.                     RequestStage prev = FinishRequestStage(RequestStage.RequestStarted);
  538.                     if (prev >= RequestStage.RequestStarted) {
  539.                         if (prev < RequestStage.ReadReady) {
  540.                             lock (m_SyncObject) {
  541.                                 if (m_RequestStage < RequestStage.ReadReady)
  542.                                     m_ReadAsyncResult = new LazyAsyncResult(null, null, null);
  543.                             }
  544.                            
  545.                             // GetRequeststream or BeginGetRequestStream has not finished yet?
  546.                             if (m_ReadAsyncResult != null)
  547.                                 m_ReadAsyncResult.InternalWaitForCompletion();
  548.                            
  549.                             CheckError();
  550.                         }
  551.                     }
  552.                     else {
  553.                         do {
  554.                             SubmitRequest(false);
  555.                             if (m_MethodInfo.IsUpload)
  556.                                 FinishRequestStage(RequestStage.WriteReady);
  557.                             else
  558.                                 FinishRequestStage(RequestStage.ReadReady);
  559.                             CheckError();
  560.                         }
  561.                         while (!CheckCacheRetrieveOnResponse());
  562.                        
  563.                         EnsureFtpWebResponse(null);
  564.                         // This may update the Stream memeber on m_FtpWebResponse based on the CacheProtocol feedback.
  565.                         CheckCacheUpdateOnResponse();
  566.                        
  567.                         if (m_FtpWebResponse.IsFromCache)
  568.                             FinishRequestStage(RequestStage.ReleaseConnection);
  569.                     }
  570.                 }
  571.             }
  572.             catch (Exception exception) {
  573.                 if (Logging.On)
  574.                     Logging.Exception(Logging.Web, this, "GetResponse", exception);
  575.                
  576.                 // if m_Exception == null, we are about to throw an exception to the user
  577.                 // and we haven't saved the exception, which also means we haven't dealt
  578.                 // with it. So just release the connection and log this for investigation
  579.                 if (m_Exception == null) {
  580.                     if (Logging.On)
  581.                         Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_unexpected_exception, "GetResponse()"));
  582.                    
  583.                     if (!NclUtilities.IsFatal(exception)) {
  584.                         GlobalLog.Assert("Find out why we are getting an unexpected exception.");
  585.                     }
  586.                     SetException(exception);
  587.                     FinishRequestStage(RequestStage.CheckForError);
  588.                 }
  589.                 throw;
  590.             }
  591.             finally {
  592.                
  593.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetResponse", "returns #" + ValidationHelper.HashString(m_FtpWebResponse));
  594.                 if (Logging.On)
  595.                     Logging.Exit(Logging.Web, this, "GetResponse", "");
  596.             }
  597.             return m_FtpWebResponse;
  598.         }
  599.        
  600.         /// <include file='doc\FtpWebRequest.uex' path='docs/doc[@for="FtpWebRequest.BeginGetResponse"]/*' />
  601.         /// <summary>
  602.         /// <para>Used to query for the Response of an FTP request [async version]</para>
  603.         /// </summary>
  604.         [HostProtection(ExternalThreading = true)]
  605.         public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
  606.         {
  607.             if (Logging.On)
  608.                 Logging.Enter(Logging.Web, this, "BeginGetResponse", "");
  609.             if (Logging.On)
  610.                 Logging.PrintInfo(Logging.Web, this, "BeginGetResponse", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method));
  611.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse");
  612.            
  613.             ContextAwareResult asyncResult;
  614.            
  615.             try {
  616.                 if (m_FtpWebResponse != null) {
  617.                     asyncResult = new ContextAwareResult(this, state, callback);
  618.                     asyncResult.InvokeCallback(m_FtpWebResponse);
  619.                     return asyncResult;
  620.                 }
  621.                
  622.                 if (m_GetResponseStarted) {
  623.                     throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  624.                 }
  625.                
  626.                 m_GetResponseStarted = true;
  627.                 CheckError();
  628.                
  629.                 if (ServicePoint.InternalProxyServicePoint) {
  630.                     HttpWebRequest httpWebRequest = GetHttpWebRequest();
  631.                     if (Logging.On)
  632.                         Logging.Associate(Logging.Web, this, httpWebRequest);
  633.                     asyncResult = (ContextAwareResult)httpWebRequest.BeginGetResponse(callback, state);
  634.                 }
  635.                 else {
  636.                     RequestStage prev = FinishRequestStage(RequestStage.RequestStarted);
  637.                     asyncResult = new ContextAwareResult(true, true, this, state, callback);
  638.                     m_ReadAsyncResult = asyncResult;
  639.                    
  640.                     if (prev >= RequestStage.RequestStarted) {
  641.                         // To make sure the context is flowed
  642.                         asyncResult.StartPostingAsyncOp();
  643.                         asyncResult.FinishPostingAsyncOp();
  644.                        
  645.                         if (prev >= RequestStage.ReadReady)
  646.                             asyncResult = null;
  647.                         else {
  648.                             lock (m_SyncObject) {
  649.                                 if (m_RequestStage >= RequestStage.ReadReady)
  650.                                     asyncResult = null;
  651.                                 ;
  652.                             }
  653.                         }
  654.                        
  655.                         if (asyncResult == null) {
  656.                             // need to complete it now
  657.                             asyncResult = (ContextAwareResult)m_ReadAsyncResult;
  658.                             if (!asyncResult.InternalPeekCompleted)
  659.                                 asyncResult.InvokeCallback();
  660.                         }
  661.                     }
  662.                     else {
  663.                         // Do internal processing in this handler to optimize context flowing.
  664.                         lock (asyncResult.StartPostingAsyncOp()) {
  665.                             SubmitRequest(true);
  666.                             asyncResult.FinishPostingAsyncOp();
  667.                         }
  668.                         FinishRequestStage(RequestStage.CheckForError);
  669.                     }
  670.                 }
  671.             }
  672.             catch (Exception exception) {
  673.                 if (Logging.On)
  674.                     Logging.Exception(Logging.Web, this, "BeginGetResponse", exception);
  675.                 throw;
  676.             }
  677.             finally {
  678.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetResponse");
  679.                 if (Logging.On)
  680.                     Logging.Exit(Logging.Web, this, "BeginGetResponse", "");
  681.             }
  682.             return asyncResult;
  683.         }
  684.        
  685.         /// <summary>
  686.         /// <para>Returns result of query for the Response of an FTP request [async version]</para>
  687.         /// </summary>
  688.         public override WebResponse EndGetResponse(IAsyncResult asyncResult)
  689.         {
  690.            
  691.             if (Logging.On)
  692.                 Logging.Enter(Logging.Web, this, "EndGetResponse", "");
  693.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse");
  694.            
  695.             try {
  696.                 // parameter validation
  697.                 if (asyncResult == null) {
  698.                     throw new ArgumentNullException("asyncResult");
  699.                 }
  700.                 LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
  701.                 if (castedAsyncResult == null) {
  702.                     throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  703.                 }
  704.                 if (HttpProxyMode ? (castedAsyncResult.AsyncObject != this.GetHttpWebRequest()) : castedAsyncResult.AsyncObject != this) {
  705.                     throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  706.                 }
  707.                 if (castedAsyncResult.EndCalled) {
  708.                     throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetResponse"));
  709.                 }
  710.                
  711.                 if (HttpProxyMode) {
  712.                     try {
  713.                         CheckError();
  714.                         if (m_FtpWebResponse == null) {
  715.                             m_FtpWebResponse = new FtpWebResponse((HttpWebResponse)GetHttpWebRequest().EndGetResponse(asyncResult));
  716.                         }
  717.                     }
  718.                     catch (WebException webException) {
  719.                         if (webException.Response != null && webException.Response is HttpWebResponse) {
  720.                             throw new WebException(webException.Message, null, webException.Status, new FtpWebResponse((HttpWebResponse)webException.Response), webException.InternalStatus);
  721.                         }
  722.                         throw;
  723.                     }
  724.                 }
  725.                 else {
  726.                     castedAsyncResult.InternalWaitForCompletion();
  727.                     castedAsyncResult.EndCalled = true;
  728.                     CheckError();
  729.                 }
  730.             }
  731.             catch (Exception exception) {
  732.                 if (Logging.On)
  733.                     Logging.Exception(Logging.Web, this, "EndGetResponse", exception);
  734.                 throw;
  735.             }
  736.             finally {
  737.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetResponse");
  738.                 if (Logging.On)
  739.                     Logging.Exit(Logging.Web, this, "EndGetResponse", "");
  740.             }
  741.             return m_FtpWebResponse;
  742.         }
  743.        
  744.        
  745.         /// <summary>
  746.         /// <para>Used to query for the Request stream of an FTP Request</para>
  747.         /// </summary>
  748.         public override Stream GetRequestStream()
  749.         {
  750.             if (Logging.On)
  751.                 Logging.Enter(Logging.Web, this, "GetRequestStream", "");
  752.             if (Logging.On)
  753.                 Logging.PrintInfo(Logging.Web, this, "GetRequestStream", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method));
  754.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream");
  755.            
  756.             try {
  757.                 if (m_GetRequestStreamStarted) {
  758.                     throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  759.                 }
  760.                 m_GetRequestStreamStarted = true;
  761.                 if (!m_MethodInfo.IsUpload) {
  762.                     throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
  763.                 }
  764.                 CheckError();
  765.                
  766.                 m_StartTime = DateTime.UtcNow;
  767.                 m_RemainingTimeout = Timeout;
  768.                
  769.                 // We don't really need this variable, but we just need
  770.                 // to call the property to measure its execution time
  771.                 ServicePoint servicePoint = ServicePoint;
  772.                
  773.                 if (Timeout != System.Threading.Timeout.Infinite) {
  774.                     m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
  775.                    
  776.                     if (m_RemainingTimeout <= 0) {
  777.                         throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
  778.                     }
  779.                 }
  780.                
  781.                
  782.                 if (ServicePoint.InternalProxyServicePoint) {
  783.                     HttpWebRequest httpWebRequest = GetHttpWebRequest();
  784.                     if (Logging.On)
  785.                         Logging.Associate(Logging.Web, this, httpWebRequest);
  786.                     m_Stream = httpWebRequest.GetRequestStream();
  787.                 }
  788.                 else {
  789.                     FinishRequestStage(RequestStage.RequestStarted);
  790.                     SubmitRequest(false);
  791.                     FinishRequestStage(RequestStage.WriteReady);
  792.                     CheckError();
  793.                 }
  794.                
  795.                 if (m_Stream.CanTimeout) {
  796.                     m_Stream.WriteTimeout = ReadWriteTimeout;
  797.                     m_Stream.ReadTimeout = ReadWriteTimeout;
  798.                 }
  799.             }
  800.             catch (Exception exception) {
  801.                 if (Logging.On)
  802.                     Logging.Exception(Logging.Web, this, "GetRequestStream", exception);
  803.                 throw;
  804.             }
  805.             finally {
  806.                
  807.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream");
  808.                 if (Logging.On)
  809.                     Logging.Exit(Logging.Web, this, "GetRequestStream", "");
  810.             }
  811.             return m_Stream;
  812.         }
  813.        
  814.         /// <summary>
  815.         /// <para>Used to query for the Request stream of an FTP Request [async version]</para>
  816.         /// </summary>
  817.         [HostProtection(ExternalThreading = true)]
  818.         public override IAsyncResult BeginGetRequestStream(AsyncCallback callback, object state)
  819.         {
  820.             if (Logging.On)
  821.                 Logging.Enter(Logging.Web, this, "BeginGetRequestStream", "");
  822.             if (Logging.On)
  823.                 Logging.PrintInfo(Logging.Web, this, "BeginGetRequestStream", SR.GetString(SR.net_log_method_equal, m_MethodInfo.Method));
  824.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream");
  825.            
  826.             ContextAwareResult asyncResult = null;
  827.            
  828.             try {
  829.                 if (m_GetRequestStreamStarted) {
  830.                     throw new InvalidOperationException(SR.GetString(SR.net_repcall));
  831.                 }
  832.                 m_GetRequestStreamStarted = true;
  833.                 if (!m_MethodInfo.IsUpload) {
  834.                     throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
  835.                 }
  836.                 CheckError();
  837.                
  838.                 if (ServicePoint.InternalProxyServicePoint) {
  839.                     HttpWebRequest httpWebRequest = GetHttpWebRequest();
  840.                     if (Logging.On)
  841.                         Logging.Associate(Logging.Web, this, httpWebRequest);
  842.                     asyncResult = (ContextAwareResult)httpWebRequest.BeginGetRequestStream(callback, state);
  843.                 }
  844.                 else {
  845.                     FinishRequestStage(RequestStage.RequestStarted);
  846.                     asyncResult = new ContextAwareResult(true, true, this, state, callback);
  847.                     lock (asyncResult.StartPostingAsyncOp()) {
  848.                         m_WriteAsyncResult = asyncResult;
  849.                         SubmitRequest(true);
  850.                         asyncResult.FinishPostingAsyncOp();
  851.                         FinishRequestStage(RequestStage.CheckForError);
  852.                     }
  853.                 }
  854.             }
  855.             catch (Exception exception) {
  856.                 if (Logging.On)
  857.                     Logging.Exception(Logging.Web, this, "BeginGetRequestStream", exception);
  858.                 throw;
  859.             }
  860.             finally {
  861.                
  862.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::BeginGetRequestStream");
  863.                 if (Logging.On)
  864.                     Logging.Exit(Logging.Web, this, "BeginGetRequestStream", "");
  865.             }
  866.             return asyncResult;
  867.         }
  868.        
  869.         public override Stream EndGetRequestStream(IAsyncResult asyncResult)
  870.         {
  871.            
  872.             if (Logging.On)
  873.                 Logging.Enter(Logging.Web, this, "EndGetRequestStream", "");
  874.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream");
  875.            
  876.             Stream requestStream = null;
  877.            
  878.             try {
  879.                 // parameter validation
  880.                 if (asyncResult == null) {
  881.                     throw new ArgumentNullException("asyncResult");
  882.                 }
  883.                
  884.                 LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
  885.                 if ((castedAsyncResult == null) || (HttpProxyMode ? (castedAsyncResult.AsyncObject != this.GetHttpWebRequest()) : castedAsyncResult.AsyncObject != this)) {
  886.                     throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
  887.                 }
  888.                
  889.                 if (castedAsyncResult.EndCalled) {
  890.                     throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetResponse"));
  891.                 }
  892.                
  893.                 if (HttpProxyMode) {
  894.                     requestStream = GetHttpWebRequest().EndGetRequestStream(asyncResult);
  895.                 }
  896.                 else {
  897.                     castedAsyncResult.InternalWaitForCompletion();
  898.                     castedAsyncResult.EndCalled = true;
  899.                     CheckError();
  900.                     requestStream = m_Stream;
  901.                     castedAsyncResult.EndCalled = true;
  902.                 }
  903.                
  904.                 if (requestStream.CanTimeout) {
  905.                     requestStream.WriteTimeout = ReadWriteTimeout;
  906.                     requestStream.ReadTimeout = ReadWriteTimeout;
  907.                 }
  908.             }
  909.             catch (Exception exception) {
  910.                 if (Logging.On)
  911.                     Logging.Exception(Logging.Web, this, "EndGetRequestStream", exception);
  912.                 throw;
  913.             }
  914.             finally {
  915.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream");
  916.                 if (Logging.On)
  917.                     Logging.Exit(Logging.Web, this, "EndGetRequestStream", "");
  918.             }
  919.             return requestStream;
  920.         }
  921.        
  922.         //
  923.         // NOTE1: The caller must synchronize access to SubmitRequest(), only one call is even allowed for a particular request!
  924.         // NOTE2: This method eats all exceptions so the caller must rethrow them
  925.         //
  926.         private void SubmitRequest(bool async)
  927.         {
  928.             try {
  929.                 m_Async = async;
  930.                
  931.                 if (CheckCacheRetrieveBeforeSubmit()) {
  932.                     RequestCallback(null);
  933.                     return;
  934.                 }
  935.                
  936.                 // This is the only place touching m_ConnectionPool
  937.                 if (m_ConnectionPool == null)
  938.                     m_ConnectionPool = ConnectionPoolManager.GetConnectionPool(ServicePoint, GetConnectionGroupLine(), m_CreateConnectionCallback);
  939.                
  940.                 //
  941.                 // FYI: Will do 2 attempts max as per AttemptedRecovery
  942.                 //
  943.                 Stream stream;
  944.                
  945.                 while (true) {
  946.                     FtpControlStream connection = m_Connection;
  947.                    
  948.                     if (connection == null) {
  949.                         connection = QueueOrCreateConnection();
  950.                         if (connection == null)
  951.                             return;
  952.                     }
  953.                    
  954.                     if (!async) {
  955.                         if (Timeout != System.Threading.Timeout.Infinite) {
  956.                             m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
  957.                            
  958.                             if (m_RemainingTimeout <= 0) {
  959.                                 throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
  960.                             }
  961.                         }
  962.                     }
  963.                    
  964.                     GlobalLog.Print("Request being submitted" + ValidationHelper.HashString(this));
  965.                     connection.SetSocketTimeoutOption(SocketShutdown.Both, RemainingTimeout, false);
  966.                    
  967.                     try {
  968.                         stream = TimedSubmitRequestHelper(async);
  969.                     }
  970.                     catch (Exception e) {
  971.                         if (AttemptedRecovery(e)) {
  972.                             if (!async) {
  973.                                 if (Timeout != System.Threading.Timeout.Infinite) {
  974.                                     m_RemainingTimeout = Timeout - (int)((DateTime.UtcNow - m_StartTime).TotalMilliseconds);
  975.                                     if (m_RemainingTimeout <= 0) {
  976.                                         throw;
  977.                                     }
  978.                                 }
  979.                             }
  980.                             continue;
  981.                         }
  982.                         throw;
  983.                     }
  984.                     // no retry needed
  985.                     break;
  986.                 }
  987.             }
  988.             catch (WebException webException) {
  989.                 //if this was a timeout, throw a timeout exception
  990.                 IOException ioEx = webException.InnerException as IOException;
  991.                 if (ioEx != null) {
  992.                     SocketException sEx = ioEx.InnerException as SocketException;
  993.                     if (sEx != null) {
  994.                         if (sEx.ErrorCode == (int)SocketError.TimedOut) {
  995.                             SetException(new WebException(SR.GetString(SR.net_timeout), WebExceptionStatus.Timeout));
  996.                         }
  997.                     }
  998.                 }
  999.                
  1000.                 SetException(webException);
  1001.             }
  1002.             catch (Exception exception) {
  1003.                 SetException(exception);
  1004.             }
  1005.         }
  1006.        
  1007.         //
  1008.         //
  1009.         //
  1010.         private FtpControlStream QueueOrCreateConnection()
  1011.         {
  1012.             FtpControlStream connection = (FtpControlStream)m_ConnectionPool.GetConnection((object)this, (m_Async ? m_AsyncCallback : null), (m_Async ? -1 : RemainingTimeout));
  1013.            
  1014.             if (connection == null) {
  1015.                 GlobalLog.Assert(m_Async, "QueueOrCreateConnection|m_ConnectionPool.GetConnection() returned null on a Sync Request.");
  1016.                 return null;
  1017.             }
  1018.            
  1019.             lock (m_SyncObject) {
  1020.                 if (m_Aborted) {
  1021.                     if (Logging.On)
  1022.                         Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection)));
  1023.                     m_ConnectionPool.PutConnection(connection, this, RemainingTimeout);
  1024.                     CheckError();
  1025.                     //must throw
  1026.                     throw new InternalException();
  1027.                 }
  1028.                 m_Connection = connection;
  1029.                 if (Logging.On)
  1030.                     Logging.Associate(Logging.Web, this, m_Connection);
  1031.             }
  1032.             return connection;
  1033.         }
  1034.         //
  1035.         //
  1036.         private Stream TimedSubmitRequestHelper(bool async)
  1037.         {
  1038.             if (async) {
  1039.                 // non-null in the case of re-submit (recovery)
  1040.                 if (m_RequestCompleteAsyncResult == null)
  1041.                     m_RequestCompleteAsyncResult = new LazyAsyncResult(null, null, null);
  1042.                 return m_Connection.SubmitRequest(this, true, true);
  1043.             }
  1044.            
  1045.             Stream stream = null;
  1046.             bool timedOut = false;
  1047.             TimerThread.Timer timer = TimerQueue.CreateTimer(m_TimerCallback, null);
  1048.             try {
  1049.                 stream = m_Connection.SubmitRequest(this, false, true);
  1050.             }
  1051.             catch (Exception exception) {
  1052.                 if (!(exception is SocketException || exception is ObjectDisposedException) || !timer.HasExpired) {
  1053.                     timer.Cancel();
  1054.                     throw;
  1055.                 }
  1056.                
  1057.                 timedOut = true;
  1058.             }
  1059.            
  1060.             if (timedOut || !timer.Cancel()) {
  1061.                 m_TimedOut = true;
  1062.                 throw new WebException(NetRes.GetWebStatusString(WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
  1063.             }
  1064.            
  1065.             if (stream != null) {
  1066.                 lock (m_SyncObject) {
  1067.                     if (m_Aborted) {
  1068.                         ((ICloseEx)stream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  1069.                         CheckError();
  1070.                         //must throw
  1071.                         throw new InternalException();
  1072.                         //consider replacing this on Assert
  1073.                     }
  1074.                     m_Stream = stream;
  1075.                 }
  1076.             }
  1077.            
  1078.             return stream;
  1079.         }
  1080.        
  1081.         /// <summary>
  1082.         /// <para>Because this is called from the timer thread, neither it nor any methods it calls can call user code.</para>
  1083.         /// </summary>
  1084.         private void TimerCallback(TimerThread.Timer timer, int timeNoticed, object context)
  1085.         {
  1086.             GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::TimerCallback");
  1087.             FtpControlStream connection = m_Connection;
  1088.             if (connection != null) {
  1089.                 GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::TimerCallback aborting connection");
  1090.                 connection.AbortConnect();
  1091.             }
  1092.         }
  1093.        
  1094.         private TimerThread.Queue TimerQueue {
  1095.             get {
  1096.                 if (m_TimerQueue == null) {
  1097.                     m_TimerQueue = TimerThread.GetOrCreateQueue(RemainingTimeout);
  1098.                 }
  1099.                
  1100.                 return m_TimerQueue;
  1101.             }
  1102.         }
  1103.        
  1104.         /// <summary>
  1105.         /// <para>Returns true if we should restart the request after an error</para>
  1106.         /// </summary>
  1107.         private bool AttemptedRecovery(Exception e)
  1108.         {
  1109.             // The first 'if' is just checking whether the exception is thrown due to the
  1110.             // relogin failure which is a recoverable error
  1111.             if (!(e is WebException && ((WebException)e).InternalStatus == WebExceptionInternalStatus.Isolated)) {
  1112.                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException || m_OnceFailed || m_Aborted || m_TimedOut || m_Connection == null || !m_Connection.RecoverableFailure) {
  1113.                     return false;
  1114.                 }
  1115.                 m_OnceFailed = true;
  1116.             }
  1117.            
  1118.             lock (m_SyncObject) {
  1119.                 if (m_ConnectionPool != null && m_Connection != null) {
  1120.                     m_Connection.CloseSocket();
  1121.                     if (Logging.On)
  1122.                         Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(m_Connection)));
  1123.                     m_ConnectionPool.PutConnection(m_Connection, this, RemainingTimeout);
  1124.                     m_Connection = null;
  1125.                 }
  1126.                 else {
  1127.                     return false;
  1128.                 }
  1129.             }
  1130.             return true;
  1131.         }
  1132.        
  1133.         /// <summary>
  1134.         /// <para>Updates and sets our exception to be thrown</para>
  1135.         /// </summary>
  1136.         private void SetException(Exception exception)
  1137.         {
  1138.            
  1139.             GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SetException");
  1140.            
  1141.             if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
  1142.                 m_Exception = exception;
  1143.                 throw exception;
  1144.             }
  1145.            
  1146.             FtpControlStream connection = m_Connection;
  1147.             if (m_Exception == null) {
  1148.                 if (exception is WebException) {
  1149.                     EnsureFtpWebResponse(exception);
  1150.                     m_Exception = new WebException(exception.Message, null, ((WebException)exception).Status, m_FtpWebResponse);
  1151.                 }
  1152.                 else if (exception is SecurityException) {
  1153.                     m_Exception = exception;
  1154.                 }
  1155.                 else if (connection != null && connection.StatusCode != FtpStatusCode.Undefined) {
  1156.                     EnsureFtpWebResponse(exception);
  1157.                     m_Exception = new WebException(SR.GetString(SR.net_servererror, connection.StatusLine), exception, WebExceptionStatus.ProtocolError, m_FtpWebResponse);
  1158.                 }
  1159.                 else {
  1160.                     m_Exception = new WebException(exception.Message, exception);
  1161.                 }
  1162.                
  1163.                 if (connection != null && m_FtpWebResponse != null)
  1164.                     m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);
  1165.             }
  1166.         }
  1167.        
  1168.         /// <summary>
  1169.         /// <para>Opposite of SetException, rethrows the exception</para>
  1170.         /// </summary>
  1171.         private void CheckError()
  1172.         {
  1173.             if (m_Exception != null) {
  1174.                 throw m_Exception;
  1175.             }
  1176.         }
  1177.        
  1178.        
  1179.         //
  1180.         // Provides an abstract way of having Async code callback into the request (saves a delegate)
  1181.         //
  1182.         // ATTN this method is also called on sync path when either command or data stream gets closed
  1183.         // Consider: Revisit the design of ftp streams
  1184.         // </STRIP>
  1185.         internal override void RequestCallback(object obj)
  1186.         {
  1187.             if (m_Async)
  1188.                 AsyncRequestCallback(obj);
  1189.             else
  1190.                 SyncRequestCallback(obj);
  1191.         }
  1192.         //
  1193.         // Only executed for Sync requests when the pipline is completed
  1194.         //
  1195.         private void SyncRequestCallback(object obj)
  1196.         {
  1197.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SyncRequestCallback", "#" + ValidationHelper.HashString(obj));
  1198.             RequestStage stageMode = RequestStage.CheckForError;
  1199.             try {
  1200.                
  1201.                 bool completedRequest = obj == null;
  1202.                 Exception exception = obj as Exception;
  1203.                
  1204.                 GlobalLog.Print("SyncRequestCallback() exp:" + ValidationHelper.HashString(exception) + " completedRequest:" + ValidationHelper.HashString(completedRequest));
  1205.                
  1206.                
  1207.                 if (exception != null) {
  1208.                     SetException(exception);
  1209.                 }
  1210.                 else if (!completedRequest) {
  1211.                     throw new InternalException();
  1212.                 }
  1213.                 else {
  1214.                     // a signal on current pipeline completion
  1215.                     FtpControlStream connection = m_Connection;
  1216.                    
  1217.                     bool isRevalidatedOrRetried = false;
  1218.                     if (connection != null) {
  1219.                         EnsureFtpWebResponse(null);
  1220.                        
  1221.                         // This to update response status and exit message if any
  1222.                         // Note that due to a design of FtpControlStream the status 221 "Service closing control connection" is always suppresses.
  1223.                         m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);
  1224.                        
  1225.                         isRevalidatedOrRetried = !m_CacheDone && (CacheProtocol.ProtocolStatus == CacheValidationStatus.Continue || CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer);
  1226.                        
  1227.                         // This is for sync Upload commands that do not get chance hit GetResponse loop
  1228.                         if (m_MethodInfo.IsUpload) {
  1229.                             CheckCacheRetrieveOnResponse();
  1230.                             CheckCacheUpdateOnResponse();
  1231.                         }
  1232.                     }
  1233.                    
  1234.                     if (!isRevalidatedOrRetried)
  1235.                         stageMode = RequestStage.ReleaseConnection;
  1236.                 }
  1237.             }
  1238.             catch (Exception exception) {
  1239.                 SetException(exception);
  1240.             }
  1241.             finally {
  1242.                 FinishRequestStage(stageMode);
  1243.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::SyncRequestCallback");
  1244.                 CheckError();
  1245.                 //will throw on error
  1246.             }
  1247.         }
  1248.         //
  1249.         // Only executed for Async requests
  1250.         //
  1251.         private void AsyncRequestCallback(object obj)
  1252.         {
  1253.             GlobalLog.Enter("FtpWebRequest#" + ValidationHelper.HashString(this) + "::AsyncRequestCallback", "#" + ValidationHelper.HashString(obj));
  1254.             RequestStage stageMode = RequestStage.CheckForError;
  1255.            
  1256.             try {
  1257.                
  1258.                 FtpControlStream connection;
  1259.                 connection = obj as FtpControlStream;
  1260.                 FtpDataStream stream = obj as FtpDataStream;
  1261.                 Exception exception = obj as Exception;
  1262.                
  1263.                 bool completedRequest = (obj == null);
  1264.                
  1265.                 GlobalLog.Print("AsyncRequestCallback() stream:" + ValidationHelper.HashString(stream) + " conn:" + ValidationHelper.HashString(connection) + " exp:" + ValidationHelper.HashString(exception) + " completedRequest:" + ValidationHelper.HashString(completedRequest));
  1266.                
  1267.                 while (true) {
  1268.                     if (exception != null) {
  1269.                         if (AttemptedRecovery(exception)) {
  1270.                             connection = QueueOrCreateConnection();
  1271.                             if (connection == null)
  1272.                                 return;
  1273.                             exception = null;
  1274.                         }
  1275.                         if (exception != null) {
  1276.                             SetException(exception);
  1277.                             break;
  1278.                         }
  1279.                     }
  1280.                    
  1281.                     if (connection != null) {
  1282.                         lock (m_SyncObject) {
  1283.                             if (m_Aborted) {
  1284.                                 if (Logging.On)
  1285.                                     Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection)));
  1286.                                 m_ConnectionPool.PutConnection(connection, this, Timeout);
  1287.                                 break;
  1288.                             }
  1289.                             m_Connection = connection;
  1290.                             if (Logging.On)
  1291.                                 Logging.Associate(Logging.Web, this, m_Connection);
  1292.                         }
  1293.                        
  1294.                         try {
  1295.                             stream = (FtpDataStream)TimedSubmitRequestHelper(true);
  1296.                         }
  1297.                         catch (Exception e) {
  1298.                             exception = e;
  1299.                             continue;
  1300.                         }
  1301.                         return;
  1302.                     }
  1303.                     else if (stream != null) {
  1304.                         lock (m_SyncObject) {
  1305.                             if (m_Aborted) {
  1306.                                 ((ICloseEx)stream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  1307.                                 break;
  1308.                             }
  1309.                             m_Stream = stream;
  1310.                         }
  1311.                        
  1312.                         stream.SetSocketTimeoutOption(SocketShutdown.Both, Timeout, true);
  1313.                         EnsureFtpWebResponse(null);
  1314.                         // This one may update the Stream member on m_FtpWebResponse based on the CacheProtocol feedback.
  1315.                         CheckCacheRetrieveOnResponse();
  1316.                         CheckCacheUpdateOnResponse();
  1317.                        
  1318.                         stageMode = stream.CanRead ? RequestStage.ReadReady : RequestStage.WriteReady;
  1319.                     }
  1320.                     else if (completedRequest) {
  1321.                         connection = m_Connection;
  1322.                        
  1323.                         bool isRevalidatedOrRetried = false;
  1324.                         if (connection != null) {
  1325.                             EnsureFtpWebResponse(null);
  1326.                            
  1327.                             // This to update response status and exit message if any
  1328.                             // Note that due to a design of FtpControlStream the status 221 "Service closing control connection" is always suppresses.
  1329.                             m_FtpWebResponse.UpdateStatus(connection.StatusCode, connection.StatusLine, connection.ExitMessage);
  1330.                            
  1331.                             isRevalidatedOrRetried = !m_CacheDone && (CacheProtocol.ProtocolStatus == CacheValidationStatus.Continue || CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer);
  1332.                            
  1333.                             lock (m_SyncObject) {
  1334.                                 if (!CheckCacheRetrieveOnResponse())
  1335.                                     continue;
  1336.                                
  1337.                                 if (m_FtpWebResponse.IsFromCache)
  1338.                                     isRevalidatedOrRetried = false;
  1339.                                
  1340.                                 CheckCacheUpdateOnResponse();
  1341.                             }
  1342.                         }
  1343.                        
  1344.                         if (!isRevalidatedOrRetried)
  1345.                             stageMode = RequestStage.ReleaseConnection;
  1346.                     }
  1347.                     else {
  1348.                         throw new InternalException();
  1349.                     }
  1350.                     break;
  1351.                 }
  1352.             }
  1353.             catch (Exception exception) {
  1354.                 SetException(exception);
  1355.             }
  1356.             catch {
  1357.                 SetException(new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  1358.             }
  1359.             finally {
  1360.                 FinishRequestStage(stageMode);
  1361.                 GlobalLog.Leave("FtpWebRequest#" + ValidationHelper.HashString(this) + "::AsyncRequestCallback");
  1362.             }
  1363.         }
  1364.        
  1365.         //
  1366.         //
  1367.         //
  1368.         private enum RequestStage
  1369.         {
  1370.             CheckForError = 0,
  1371.             // Do nothing except if there is an error then auto promote to ReleaseConnection
  1372.             RequestStarted,
  1373.             // Mark this request as started
  1374.             WriteReady,
  1375.             // First half is done, i.e. either writer or response stream. This is always assumed unless Started or CheckForError
  1376.             ReadReady,
  1377.             // Second half is done, i.e. the read stream can be accesses.
  1378.             ReleaseConnection
  1379.             // Release the control connection (request is read i.e. done-done)
  1380.         }
  1381.         //
  1382.         // Returns a previous stage
  1383.         //
  1384.         private RequestStage FinishRequestStage(RequestStage stage)
  1385.         {
  1386.             GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::FinishRequestStage : stage=" + stage);
  1387.             if (m_Exception != null)
  1388.                 stage = RequestStage.ReleaseConnection;
  1389.            
  1390.             RequestStage prev;
  1391.             LazyAsyncResult writeResult;
  1392.             LazyAsyncResult readResult;
  1393.             FtpControlStream connection;
  1394.            
  1395.             lock (m_SyncObject) {
  1396.                 prev = m_RequestStage;
  1397.                
  1398.                 if (stage == RequestStage.CheckForError)
  1399.                     return prev;
  1400.                
  1401.                 if (prev == RequestStage.ReleaseConnection && stage == RequestStage.ReleaseConnection) {
  1402.                     return RequestStage.ReleaseConnection;
  1403.                 }
  1404.                
  1405.                 if (stage > prev)
  1406.                     m_RequestStage = stage;
  1407.                
  1408.                 if (stage <= RequestStage.RequestStarted)
  1409.                     return prev;
  1410.                
  1411.                 writeResult = m_WriteAsyncResult;
  1412.                 readResult = m_ReadAsyncResult;
  1413.                 connection = m_Connection;
  1414.                
  1415.                 if (stage == RequestStage.ReleaseConnection) {
  1416.                     if (m_Exception == null && !m_Aborted && prev != RequestStage.ReadReady && this.m_MethodInfo.IsDownload && !m_FtpWebResponse.IsFromCache) {
  1417.                         return prev;
  1418.                     }
  1419.                     if (m_Exception != null || !(m_FtpWebResponse.IsFromCache && !KeepAlive))
  1420.                         m_Connection = null;
  1421.                 }
  1422.             }
  1423.            
  1424.             try {
  1425.                 // First check to see on releasing the connection
  1426.                 if ((stage == RequestStage.ReleaseConnection || prev == RequestStage.ReleaseConnection) && connection != null) {
  1427.                     try {
  1428.                         if (m_Exception != null) {
  1429.                             connection.Abort(m_Exception);
  1430.                         }
  1431.                         else if (m_FtpWebResponse.IsFromCache && !KeepAlive) {
  1432.                             // This means the response has been revalidated and found as good means the commands pipleline is completed.
  1433.                             // Now if this request was NOT KeepAlive we want to be fair and close the control connection.
  1434.                             // That becomes unnecessary complicated in the async case to support "QUIT" command semantic, so simply close the socket
  1435.                             // and let pool collect the object.
  1436.                             connection.Quit();
  1437.                         }
  1438.                     }
  1439.                     finally {
  1440.                         if (Logging.On)
  1441.                             Logging.PrintInfo(Logging.Web, this, "", SR.GetString(SR.net_log_releasing_connection, ValidationHelper.HashString(connection)));
  1442.                         m_ConnectionPool.PutConnection(connection, this, RemainingTimeout);
  1443.                         if (m_Async)
  1444.                             if (m_RequestCompleteAsyncResult != null)
  1445.                                 m_RequestCompleteAsyncResult.InvokeCallback();
  1446.                     }
  1447.                 }
  1448.                 return prev;
  1449.             }
  1450.             finally {
  1451.                 try {
  1452.                     // In any case we want to signal the writer if came here
  1453.                     if (stage >= RequestStage.WriteReady) {
  1454.                         // If writeResult == null and this is an upload request, it means
  1455.                         // that the user has called GetResponse() without calling
  1456.                         // GetRequestStream() first. So they are not interested in a
  1457.                         // stream. Therefore we close the stream so that the
  1458.                         // request/pipeline can continue
  1459.                         if (m_MethodInfo.IsUpload && !m_GetRequestStreamStarted) {
  1460.                             if (m_Stream != null)
  1461.                                 m_Stream.Close();
  1462.                         }
  1463.                         else if (writeResult != null && !writeResult.InternalPeekCompleted)
  1464.                             writeResult.InvokeCallback();
  1465.                     }
  1466.                 }
  1467.                 finally {
  1468.                     // The response is ready either with or without a stream
  1469.                     if (stage >= RequestStage.ReadReady && readResult != null && !readResult.InternalPeekCompleted)
  1470.                         readResult.InvokeCallback();
  1471.                 }
  1472.             }
  1473.         }
  1474.        
  1475.         //
  1476.         // Used only in the async case and only for the initial callback from the pool when connection is established.
  1477.         //
  1478.         private static void AsyncCallbackWrapper(object request, object state)
  1479.         {
  1480.             FtpWebRequest ftpWebRequest = (FtpWebRequest)request;
  1481.             ftpWebRequest.RequestCallback(state);
  1482.         }
  1483.        
  1484.         /// <summary>
  1485.         /// <para>builds networkStream from Socket</para>
  1486.         /// </summary>
  1487.         private static PooledStream CreateFtpConnection(ConnectionPool pool)
  1488.         {
  1489.             return (PooledStream)new FtpControlStream(pool, TimeSpan.MaxValue, false);
  1490.         }
  1491.        
  1492.         /// <summary>
  1493.         /// <para>Aborts underlying connection to FTP server (command & data)</para>
  1494.         /// </summary>
  1495.         public override void Abort()
  1496.         {
  1497.             if (m_Aborted)
  1498.                 return;
  1499.            
  1500.             if (Logging.On)
  1501.                 Logging.Enter(Logging.Web, this, "Abort", "");
  1502.            
  1503.             try {
  1504.                
  1505.                 GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::Abort()");
  1506.                
  1507.                 if (HttpProxyMode) {
  1508.                     GetHttpWebRequest().Abort();
  1509.                     return;
  1510.                 }
  1511.                
  1512.                 if (CacheProtocol != null)
  1513.                     CacheProtocol.Abort();
  1514.                
  1515.                 Stream stream;
  1516.                 FtpControlStream connection;
  1517.                 lock (m_SyncObject) {
  1518.                     if (m_RequestStage >= RequestStage.ReleaseConnection)
  1519.                         return;
  1520.                     m_Aborted = true;
  1521.                     stream = m_Stream;
  1522.                     connection = m_Connection;
  1523.                     m_Exception = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled);
  1524.                 }
  1525.                
  1526.                 if (stream != null) {
  1527.                     GlobalLog.Assert(stream is ICloseEx, "FtpWebRequest.Abort()|The m_Stream member is not CloseEx hence the risk of connection been orphaned.");
  1528.                     ((ICloseEx)stream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  1529.                 }
  1530.                 if (connection != null)
  1531.                     connection.Abort(ExceptionHelper.RequestAbortedException);
  1532.                
  1533.             }
  1534.             catch (Exception exception) {
  1535.                 if (Logging.On)
  1536.                     Logging.Exception(Logging.Web, this, "Abort", exception);
  1537.                 throw;
  1538.             }
  1539.             finally {
  1540.                 if (Logging.On)
  1541.                     Logging.Exit(Logging.Web, this, "Abort", "");
  1542.             }
  1543.         }
  1544.        
  1545.         /// <include file='doc\FtpWebRequest.uex' path='docs/doc[@for="FtpWebRequest.KeepAlive"]/*' />
  1546.         /// <summary>
  1547.         /// <para>
  1548.         /// If KeepAlive is set to false, then the control connection to the server will be closed when the request completes.
  1549.         /// Default is true
  1550.         /// </para>
  1551.         /// </summary>
  1552.         public bool KeepAlive {
  1553.             get { return m_KeepAlive; }
  1554.             set {
  1555.                 if (InUse) {
  1556.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  1557.                 }
  1558.                 m_KeepAlive = value;
  1559.             }
  1560.         }
  1561.        
  1562.         /// <summary>
  1563.         /// <para>True by default, false allows transmission using text mode</para>
  1564.         /// </summary>
  1565.         public bool UseBinary {
  1566.             get { return m_Binary; }
  1567.             set {
  1568.                 if (InUse) {
  1569.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  1570.                 }
  1571.                 m_Binary = value;
  1572.             }
  1573.         }
  1574.        
  1575.         /// <summary>
  1576.         /// <para>False by default, true enables passive mode communication with server.
  1577.         /// This alters the way the client talks with the server, allowing the client
  1578.         /// to initiate the data connection with the server</para>
  1579.         /// </summary>
  1580.         public bool UsePassive {
  1581.             get { return m_Passive; }
  1582.             set {
  1583.                 if (InUse) {
  1584.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  1585.                 }
  1586.                 m_Passive = value;
  1587.             }
  1588.         }
  1589.        
  1590.        
  1591.         /// <summary>
  1592.         /// <para>Set to true if we need SSL</para>
  1593.         /// </summary>
  1594.         public bool EnableSsl {
  1595.             get { return m_EnableSsl; }
  1596.             set {
  1597.                 if (InUse) {
  1598.                     throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
  1599.                 }
  1600.                 m_EnableSsl = value;
  1601.             }
  1602.         }
  1603.        
  1604.        
  1605.         /// <devdoc>
  1606.         /// <para>
  1607.         /// A collection of headers, currently nothing is return except an empty collection
  1608.         /// </para>
  1609.         /// </devdoc>
  1610.         public override WebHeaderCollection Headers {
  1611.             get {
  1612.                 if (HttpProxyMode) {
  1613.                     return GetHttpWebRequest().Headers;
  1614.                 }
  1615.                 if (m_FtpRequestHeaders == null) {
  1616.                     m_FtpRequestHeaders = new WebHeaderCollection(WebHeaderCollectionType.FtpWebRequest);
  1617.                 }
  1618.                 return m_FtpRequestHeaders;
  1619.             }
  1620.             set {
  1621.                 if (HttpProxyMode) {
  1622.                     GetHttpWebRequest().Headers = value;
  1623.                 }
  1624.                 m_FtpRequestHeaders = value;
  1625.             }
  1626.         }
  1627.        
  1628.         // NOT SUPPORTED method
  1629.         public override string ContentType {
  1630.             get {
  1631.                 throw ExceptionHelper.PropertyNotSupportedException;
  1632.             }
  1633.             set {
  1634.                 throw ExceptionHelper.PropertyNotSupportedException;
  1635.             }
  1636.         }
  1637.        
  1638.         // NOT SUPPORTED method
  1639.         public override bool UseDefaultCredentials {
  1640.             get {
  1641.                 throw ExceptionHelper.PropertyNotSupportedException;
  1642.             }
  1643.             set {
  1644.                 throw ExceptionHelper.PropertyNotSupportedException;
  1645.             }
  1646.         }
  1647.        
  1648.         // NOT SUPPORTED method
  1649.         public override bool PreAuthenticate {
  1650.             get {
  1651.                 throw ExceptionHelper.PropertyNotSupportedException;
  1652.             }
  1653.             set {
  1654.                 throw ExceptionHelper.PropertyNotSupportedException;
  1655.             }
  1656.         }
  1657.        
  1658.         /// <summary>
  1659.         /// <para>True if a request has been submitted (ie already active)</para>
  1660.         /// </summary>
  1661.         private bool InUse {
  1662.             get {
  1663.                 if (m_GetRequestStreamStarted || m_GetResponseStarted) {
  1664.                     return true;
  1665.                 }
  1666.                 else {
  1667.                     return false;
  1668.                 }
  1669.             }
  1670.         }
  1671.        
  1672.         /// <summary>
  1673.         /// <para>True if request is just wrapping HttpWebRequest</para>
  1674.         /// </summary>
  1675.         private bool HttpProxyMode {
  1676.             get { return (m_HttpWebRequest != null); }
  1677.         }
  1678.        
  1679.        
  1680.         /// <summary>
  1681.         /// <para>Creates an FTP WebResponse based off the responseStream and our active Connection</para>
  1682.         /// </summary>
  1683.         private void EnsureFtpWebResponse(Exception exception)
  1684.         {
  1685.             if (m_FtpWebResponse == null || (m_FtpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && m_Stream != null)) {
  1686.                 lock (m_SyncObject) {
  1687.                     if (m_FtpWebResponse == null || (m_FtpWebResponse.GetResponseStream() is FtpWebResponse.EmptyStream && m_Stream != null)) {
  1688.                         Stream responseStream = m_Stream;
  1689.                        
  1690.                         if (m_MethodInfo.IsUpload) {
  1691.                             responseStream = null;
  1692.                         }
  1693.                        
  1694.                         if (m_Stream != null && m_Stream.CanRead && m_Stream.CanTimeout) {
  1695.                             m_Stream.ReadTimeout = ReadWriteTimeout;
  1696.                             m_Stream.WriteTimeout = ReadWriteTimeout;
  1697.                         }
  1698.                        
  1699.                         FtpControlStream connection = m_Connection;
  1700.                         long contentLength = connection != null ? connection.ContentLength : -1;
  1701.                        
  1702.                         if (responseStream == null) {
  1703.                            
  1704.                             // If the last command was SIZE, we set the ContentLength on
  1705.                             // the FtpControlStream to be the size of the file returned in the
  1706.                             // response. We should propagate that file size to the response so
  1707.                             // users can access it. This also maintains the compatibility with
  1708.                             // HTTP when returning size instead of content.
  1709.                             if (contentLength < 0)
  1710.                                 contentLength = 0;
  1711.                         }
  1712.                        
  1713.                         if (m_FtpWebResponse != null) {
  1714.                             m_FtpWebResponse.SetResponseStream(responseStream);
  1715.                         }
  1716.                         else {
  1717.                             if (connection != null)
  1718.                                 m_FtpWebResponse = new FtpWebResponse(responseStream, contentLength, connection.ResponseUri, connection.StatusCode, connection.StatusLine, connection.LastModified, connection.BannerMessage, connection.WelcomeMessage, connection.ExitMessage);
  1719.                             else
  1720.                                 m_FtpWebResponse = new FtpWebResponse(responseStream, -1, m_Uri, FtpStatusCode.Undefined, null, DateTime.Now, null, null, null);
  1721.                         }
  1722.                     }
  1723.                 }
  1724.             }
  1725.            
  1726.             GlobalLog.Print("FtpWebRequest#" + ValidationHelper.HashString(this) + "::EnsureFtpWebResponse returns #" + ValidationHelper.HashString(m_FtpWebResponse) + " with stream#" + ValidationHelper.HashString(m_FtpWebResponse.m_ResponseStream));
  1727.             return;
  1728.         }
  1729.        
  1730.         /// <summary>
  1731.         /// <para>Creates a HttpWebRequest</para>
  1732.         /// </summary>
  1733.         private HttpWebRequest GetHttpWebRequest()
  1734.         {
  1735.             lock (m_SyncObject) {
  1736.                 if (m_HttpWebRequest == null) {
  1737.                     if (m_ContentOffset > 0) {
  1738.                         throw new InvalidOperationException(SR.GetString(SR.net_ftp_no_offsetforhttp));
  1739.                     }
  1740.                    
  1741.                     if (!m_MethodInfo.HasHttpCommand)
  1742.                         throw new InvalidOperationException(SR.GetString(SR.net_ftp_no_http_cmd));
  1743.                    
  1744.                     m_HttpWebRequest = new HttpWebRequest(m_Uri, ServicePoint);
  1745.                     m_HttpWebRequest.Credentials = Credentials;
  1746.                     m_HttpWebRequest.InternalProxy = m_Proxy;
  1747.                     m_HttpWebRequest.KeepAlive = KeepAlive;
  1748.                     m_HttpWebRequest.Timeout = Timeout;
  1749.                     m_HttpWebRequest.Method = m_MethodInfo.HttpCommand;
  1750.                     m_HttpWebRequest.CacheProtocol = CacheProtocol;
  1751.                     RequestCacheLevel effectiveLevel;
  1752.                     if (CachePolicy == null)
  1753.                         effectiveLevel = RequestCacheLevel.BypassCache;
  1754.                     else
  1755.                         effectiveLevel = CachePolicy.Level;
  1756.                    
  1757.                     // Cannot support revalidate through the proxy
  1758.                     if (effectiveLevel == RequestCacheLevel.Revalidate)
  1759.                         effectiveLevel = RequestCacheLevel.Reload;
  1760.                     m_HttpWebRequest.CachePolicy = new HttpRequestCachePolicy((HttpRequestCacheLevel)effectiveLevel);
  1761.                    
  1762.                     //disable cache protocol on that class since we are proxying through HTTP
  1763.                     CacheProtocol = null;
  1764.                    
  1765.                 }
  1766.             }
  1767.             return m_HttpWebRequest;
  1768.         }
  1769.        
  1770.        
  1771.         /// <devdoc>
  1772.         /// <para>Generates a string that
  1773.         /// allows a Connection to remain unique for user
  1774.         /// this is needed to prevent multiple users from
  1775.         /// using the same sockets after they mess with things</para>
  1776.         /// </devdoc>
  1777.         private string GetConnectionGroupLine()
  1778.         {
  1779.             GlobalLog.Print("GetConnectionGroupLine");
  1780.             return ConnectionGroupName;
  1781.         }
  1782.        
  1783.        
  1784.         /// <summary>
  1785.         /// <para>Returns username string</para>
  1786.         /// </summary>
  1787.         internal string GetUserString()
  1788.         {
  1789.             string name = null;
  1790.             if (this.Credentials != null) {
  1791.                 NetworkCredential networkCreds = this.Credentials.GetCredential(m_Uri, "basic");
  1792.                 if (networkCreds != null) {
  1793.                     name = networkCreds.InternalGetUserName();
  1794.                     string domain = networkCreds.InternalGetDomain();
  1795.                     if (!ValidationHelper.IsBlankString(domain)) {
  1796.                         name = domain + "\\" + name;
  1797.                     }
  1798.                 }
  1799.             }
  1800.             return name == null ? null : (String.Compare(name, "anonymous", StringComparison.InvariantCultureIgnoreCase) == 0 ? null : name);
  1801.         }
  1802.        
  1803.         //
  1804.         // This method may be invoked as part of the request submission but
  1805.         // before the response is received
  1806.         // Return:
  1807.         // - True = Use CacheProtocol properties to create the cached response
  1808.         // - False = Proceed with the request submission
  1809.         private bool CheckCacheRetrieveBeforeSubmit()
  1810.         {
  1811.            
  1812.             if (CacheProtocol == null || m_CacheDone) {
  1813.                 m_CacheDone = true;
  1814.                 return false;
  1815.             }
  1816.            
  1817.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse || CacheProtocol.ProtocolStatus == CacheValidationStatus.DoNotTakeFromCache) {
  1818.                 // Re-entry into a new pipeline on failed revalidate or combining cached and live streams
  1819.                 return false;
  1820.             }
  1821.            
  1822.             Uri cacheUri = RequestUri;
  1823.             string username = GetUserString();
  1824.             if (username != null)
  1825.                 username = Uri.EscapeDataString(username);
  1826.            
  1827.             if (cacheUri.Fragment.Length != 0 || username != null) {
  1828.                 if (username == null)
  1829.                     cacheUri = new Uri(cacheUri.GetParts(UriComponents.AbsoluteUri & ~(UriComponents.Fragment | UriComponents.UserInfo), UriFormat.SafeUnescaped));
  1830.                 else {
  1831.                     username = cacheUri.GetParts((UriComponents.Scheme | UriComponents.KeepDelimiter), UriFormat.SafeUnescaped) + username + '@';
  1832.                     username += cacheUri.GetParts((UriComponents.Host | UriComponents.Port | UriComponents.Path | UriComponents.Query), UriFormat.SafeUnescaped);
  1833.                     cacheUri = new Uri(username);
  1834.                 }
  1835.             }
  1836.            
  1837.             CacheProtocol.GetRetrieveStatus(cacheUri, this);
  1838.            
  1839.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) {
  1840.                 throw CacheProtocol.ProtocolException;
  1841.             }
  1842.            
  1843.             if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) {
  1844.                 return false;
  1845.             }
  1846.            
  1847.             if (m_MethodInfo.Operation != FtpOperation.DownloadFile) {
  1848.                 throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_command));
  1849.             }
  1850.            
  1851.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.ReturnCachedResponse) {
  1852.                 // If we take it from cache, we have to kick in response processing
  1853.                 // The _CacheStream is good to return as the response stream.
  1854.                 FtpRequestCacheValidator ctx = (FtpRequestCacheValidator)CacheProtocol.Validator;
  1855.                 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);
  1856.                
  1857.                 m_FtpWebResponse.InternalSetFromCache = true;
  1858.                 m_FtpWebResponse.InternalSetIsCacheFresh = (ctx.CacheFreshnessStatus != CacheFreshnessStatus.Stale);
  1859.             }
  1860.             return true;
  1861.         }
  1862.        
  1863.         //
  1864.         // This method has to be invoked as part of the wire response processing.
  1865.         // The wire response can be replaced on return
  1866.         //
  1867.         // ATTN: If the method returns false, the response is invalid and should be retried
  1868.         //
  1869.         private bool CheckCacheRetrieveOnResponse()
  1870.         {
  1871.            
  1872.             if (CacheProtocol == null || m_CacheDone) {
  1873.                 return true;
  1874.             }
  1875.            
  1876.             if (CacheProtocol.ProtocolStatus != CacheValidationStatus.Continue) {
  1877.                 // cache has been already revalidated proceed with cache update
  1878.                 return true;
  1879.             }
  1880.            
  1881.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) {
  1882.                 if (Logging.On)
  1883.                     Logging.Exception(Logging.Web, this, "CheckCacheRetrieveOnResponse", CacheProtocol.ProtocolException);
  1884.                 throw CacheProtocol.ProtocolException;
  1885.             }
  1886.            
  1887.             // At this point we dont have the real data stream, hence passing null and updating it later
  1888.             CacheProtocol.GetRevalidateStatus(m_FtpWebResponse, null);
  1889.            
  1890.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer) {
  1891.                 if (m_FtpWebResponse != null)
  1892.                     m_FtpWebResponse.SetResponseStream(null);
  1893.                 //prevent from advancing commands pipeline
  1894.                 // Try to resubmit or fail
  1895.                 return false;
  1896.             }
  1897.            
  1898.             if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) {
  1899.                 // Proceed with the requesting the real server data stream
  1900.                 return false;
  1901.             }
  1902.            
  1903.             if (m_MethodInfo.Operation != FtpOperation.DownloadFile) {
  1904.                 // This should never happen in real life
  1905.                 throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_command));
  1906.             }
  1907.            
  1908.            
  1909.             FtpRequestCacheValidator ctx = (FtpRequestCacheValidator)CacheProtocol.Validator;
  1910.            
  1911.             FtpWebResponse oldResponse = m_FtpWebResponse;
  1912.             m_Stream = CacheProtocol.ResponseStream;
  1913.             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);
  1914.            
  1915.             m_FtpWebResponse.InternalSetFromCache = true;
  1916.             m_FtpWebResponse.InternalSetIsCacheFresh = CacheProtocol.IsCacheFresh;
  1917.            
  1918.             oldResponse.Close();
  1919.             return true;
  1920.         }
  1921.        
  1922.        
  1923.        
  1924.         //
  1925.         // This will decide on cache update and construct the effective response stream
  1926.         //
  1927.         private void CheckCacheUpdateOnResponse()
  1928.         {
  1929.             if (CacheProtocol == null || m_CacheDone) {
  1930.                 return;
  1931.             }
  1932.             m_CacheDone = true;
  1933.            
  1934.             if (m_Connection != null) {
  1935.                 m_FtpWebResponse.UpdateStatus(m_Connection.StatusCode, m_Connection.StatusLine, m_Connection.ExitMessage);
  1936.                 if (m_Connection.StatusCode == FtpStatusCode.OpeningData && m_FtpWebResponse.ContentLength == 0)
  1937.                     m_FtpWebResponse.SetContentLength(m_Connection.ContentLength);
  1938.             }
  1939.            
  1940.             if (CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse) {
  1941.                 // Note we already asked for a file restart
  1942.                 // The only problem is that we could not create the combined stream sooner.
  1943.                 m_Stream = new CombinedReadStream(CacheProtocol.Validator.CacheStream, m_FtpWebResponse.GetResponseStream());
  1944.                 //
  1945.                 // For consitent user expirience we always supply DataAlreadyOpen status for a cached response.
  1946.                 //
  1947.                 FtpStatusCode rightStatus = UsePassive ? FtpStatusCode.DataAlreadyOpen : FtpStatusCode.OpeningData;
  1948.                
  1949.                 m_FtpWebResponse.UpdateStatus(rightStatus, rightStatus.ToString(), string.Empty);
  1950.                 m_FtpWebResponse.SetResponseStream(m_Stream);
  1951.             }
  1952.            
  1953.             if (CacheProtocol.GetUpdateStatus(m_FtpWebResponse, m_FtpWebResponse.GetResponseStream()) == CacheValidationStatus.UpdateResponseInformation) {
  1954.                 m_Stream = CacheProtocol.ResponseStream;
  1955.                 m_FtpWebResponse.SetResponseStream(m_Stream);
  1956.             }
  1957.             else if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail)
  1958.                 throw CacheProtocol.ProtocolException;
  1959.         }
  1960.        
  1961.         internal void DataStreamClosed(CloseExState closeState)
  1962.         {
  1963.             if ((closeState & CloseExState.Abort) == 0) {
  1964.                 if (!m_Async) {
  1965.                     if (m_Connection != null)
  1966.                         m_Connection.CheckContinuePipeline();
  1967.                 }
  1968.                 else {
  1969.                     m_RequestCompleteAsyncResult.InternalWaitForCompletion();
  1970.                     CheckError();
  1971.                 }
  1972.             }
  1973.             else {
  1974.                 FtpControlStream connection = m_Connection;
  1975.                 if (connection != null)
  1976.                     connection.Abort(ExceptionHelper.RequestAbortedException);
  1977.             }
  1978.         }
  1979.     }
  1980.     // class FtpWebRequest
  1981.     //
  1982.     // Class used by the WebRequest.Create factory to create FTP requests
  1983.     //
  1984.     internal class FtpWebRequestCreator : IWebRequestCreate
  1985.     {
  1986.         internal FtpWebRequestCreator()
  1987.         {
  1988.         }
  1989.         public WebRequest Create(Uri uri)
  1990.         {
  1991.             return new FtpWebRequest(uri);
  1992.         }
  1993.     }
  1994.     // class FtpWebRequestCreator
  1995. }
  1996. //namespace System.Net

Developer Fusion