2 // System.Net.FtpWebRequest.cs
5 // Carlos Alberto Cortez (calberto.cortez@gmail.com)
7 // (c) Copyright 2006 Novell, Inc. (http://www.novell.com)
13 using System.Net.Sockets;
15 using System.Threading;
16 using System.Net.Cache;
17 using System.Security.Cryptography.X509Certificates;
23 public sealed class FtpWebRequest : WebRequest
26 string file_name; // By now, used for upload
27 ServicePoint servicePoint;
29 NetworkStream controlStream;
30 StreamReader controlReader;
31 NetworkCredential credentials;
32 IPHostEntry hostEntry;
33 IPEndPoint localEndPoint;
36 int rwTimeout = 300000;
39 bool enableSsl = false;
40 bool usePassive = true;
41 bool keepAlive = false;
42 string method = WebRequestMethods.Ftp.DownloadFile;
44 object locker = new object ();
46 RequestState requestState = RequestState.Before;
47 FtpAsyncResult asyncResult;
48 FtpWebResponse ftpResponse;
52 const string ChangeDir = "CWD";
53 const string UserCommand = "USER";
54 const string PasswordCommand = "PASS";
55 const string TypeCommand = "TYPE";
56 const string PassiveCommand = "PASV";
57 const string PortCommand = "PORT";
58 const string AbortCommand = "ABOR";
59 const string AuthCommand = "AUTH";
60 const string RestCommand = "REST";
61 const string RenameFromCommand = "RNFR";
62 const string RenameToCommand = "RNTO";
63 const string QuitCommand = "QUIT";
64 const string EOL = "\r\n"; // Special end of line
80 static readonly string [] supportedCommands = new string [] {
81 WebRequestMethods.Ftp.AppendFile, // APPE
82 WebRequestMethods.Ftp.DeleteFile, // DELE
83 WebRequestMethods.Ftp.ListDirectoryDetails, // LIST
84 WebRequestMethods.Ftp.GetDateTimestamp, // MDTM
85 WebRequestMethods.Ftp.MakeDirectory, // MKD
86 WebRequestMethods.Ftp.ListDirectory, // NLST
87 WebRequestMethods.Ftp.PrintWorkingDirectory, // PWD
88 WebRequestMethods.Ftp.Rename, // RENAME
89 WebRequestMethods.Ftp.DownloadFile, // RETR
90 WebRequestMethods.Ftp.RemoveDirectory, // RMD
91 WebRequestMethods.Ftp.GetFileSize, // SIZE
92 WebRequestMethods.Ftp.UploadFile, // STOR
93 WebRequestMethods.Ftp.UploadFileWithUniqueName // STUR
96 internal FtpWebRequest (Uri uri)
98 this.requestUri = uri;
99 this.proxy = GlobalProxySelection.Select;
102 static Exception GetMustImplement ()
104 return new NotImplementedException ();
108 public X509CertificateCollection ClientCertificates
111 throw GetMustImplement ();
114 throw GetMustImplement ();
119 public override string ConnectionGroupName
122 throw GetMustImplement ();
125 throw GetMustImplement ();
129 public override string ContentType {
131 throw new NotSupportedException ();
134 throw new NotSupportedException ();
138 public override long ContentLength {
147 public long ContentOffset {
152 CheckRequestStarted ();
154 throw new ArgumentOutOfRangeException ();
160 public override ICredentials Credentials {
165 CheckRequestStarted ();
167 throw new ArgumentNullException ();
168 if (!(value is NetworkCredential))
169 throw new ArgumentException ();
171 credentials = value as NetworkCredential;
176 public static new RequestCachePolicy DefaultCachePolicy
179 throw GetMustImplement ();
182 throw GetMustImplement ();
186 public bool EnableSsl {
191 CheckRequestStarted ();
197 public override WebHeaderCollection Headers
200 throw GetMustImplement ();
203 throw GetMustImplement ();
207 [MonoTODO ("We don't support KeepAlive = true")]
208 public bool KeepAlive {
213 CheckRequestStarted ();
218 public override string Method {
223 CheckRequestStarted ();
225 throw new ArgumentNullException ("Method string cannot be null");
227 if (value.Length == 0 || Array.BinarySearch (supportedCommands, value) < 0)
228 throw new ArgumentException ("Method not supported", "value");
234 public override bool PreAuthenticate {
236 throw new NotSupportedException ();
239 throw new NotSupportedException ();
243 public override IWebProxy Proxy {
248 CheckRequestStarted ();
250 throw new ArgumentNullException ();
256 public int ReadWriteTimeout {
261 CheckRequestStarted ();
264 throw new ArgumentOutOfRangeException ();
270 public string RenameTo {
275 CheckRequestStarted ();
276 if (value == null || value.Length == 0)
277 throw new ArgumentException ("RenameTo value can't be null or empty", "RenameTo");
283 public override Uri RequestUri {
289 public ServicePoint ServicePoint {
291 return GetServicePoint ();
295 public bool UsePassive {
300 CheckRequestStarted ();
306 public override bool UseDefaultCredentials
309 throw GetMustImplement ();
312 throw GetMustImplement ();
316 public bool UseBinary {
320 CheckRequestStarted ();
325 public override int Timeout {
330 CheckRequestStarted ();
333 throw new ArgumentOutOfRangeException ();
341 return binary ? "I" : "A";
356 requestState = value;
361 public override void Abort () {
363 if (State == RequestState.TransferInProgress) {
364 /*FtpStatus status = */
365 SendCommand (false, AbortCommand);
368 if (!InFinalState ()) {
369 State = RequestState.Aborted;
370 ftpResponse = new FtpWebResponse (this, requestUri, method, FtpStatusCode.FileActionAborted, "Aborted by request");
375 public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state) {
376 if (asyncResult != null && !asyncResult.IsCompleted) {
377 throw new InvalidOperationException ("Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call is still in progress");
382 asyncResult = new FtpAsyncResult (callback, state);
386 asyncResult.SetCompleted (true, ftpResponse);
388 if (State == RequestState.Before)
389 State = RequestState.Scheduled;
391 Thread thread = new Thread (ProcessRequest);
399 public override WebResponse EndGetResponse (IAsyncResult asyncResult) {
400 if (asyncResult == null)
401 throw new ArgumentNullException ("AsyncResult cannot be null!");
403 if (!(asyncResult is FtpAsyncResult) || asyncResult != this.asyncResult)
404 throw new ArgumentException ("AsyncResult is from another request!");
406 FtpAsyncResult asyncFtpResult = (FtpAsyncResult) asyncResult;
407 if (!asyncFtpResult.WaitUntilComplete (timeout, false)) {
409 throw new WebException ("Transfer timed out.", WebExceptionStatus.Timeout);
416 if (asyncFtpResult.GotException)
417 throw asyncFtpResult.Exception;
419 return asyncFtpResult.Response;
422 public override WebResponse GetResponse () {
423 IAsyncResult asyncResult = BeginGetResponse (null, null);
424 return EndGetResponse (asyncResult);
427 public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) {
428 if (method != WebRequestMethods.Ftp.UploadFile && method != WebRequestMethods.Ftp.UploadFileWithUniqueName &&
429 method != WebRequestMethods.Ftp.AppendFile)
430 throw new ProtocolViolationException ();
435 if (State != RequestState.Before)
436 throw new InvalidOperationException ("Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call is still in progress");
438 State = RequestState.Scheduled;
441 asyncResult = new FtpAsyncResult (callback, state);
442 Thread thread = new Thread (ProcessRequest);
448 public override Stream EndGetRequestStream (IAsyncResult asyncResult) {
449 if (asyncResult == null)
450 throw new ArgumentNullException ("asyncResult");
452 if (!(asyncResult is FtpAsyncResult))
453 throw new ArgumentException ("asyncResult");
455 if (State == RequestState.Aborted) {
456 throw new WebException ("Request aborted", WebExceptionStatus.RequestCanceled);
459 if (asyncResult != this.asyncResult)
460 throw new ArgumentException ("AsyncResult is from another request!");
462 FtpAsyncResult res = (FtpAsyncResult) asyncResult;
464 if (!res.WaitUntilComplete (timeout, false)) {
466 throw new WebException ("Request timed out");
469 if (res.GotException)
475 public override Stream GetRequestStream () {
476 IAsyncResult asyncResult = BeginGetRequestStream (null, null);
477 return EndGetRequestStream (asyncResult);
480 ServicePoint GetServicePoint ()
482 if (servicePoint == null)
483 servicePoint = ServicePointManager.FindServicePoint (requestUri, proxy);
488 // Probably move some code of command connection here
492 hostEntry = GetServicePoint ().HostEntry;
494 if (hostEntry == null) {
495 ftpResponse.UpdateStatus (new FtpStatus(FtpStatusCode.ActionAbortedLocalProcessingError, "Cannot resolve server name"));
496 throw new WebException ("The remote server name could not be resolved: " + requestUri,
497 null, WebExceptionStatus.NameResolutionFailure, ftpResponse);
501 void ProcessRequest () {
503 if (State == RequestState.Scheduled) {
504 ftpResponse = new FtpWebResponse (this, requestUri, method, keepAlive);
508 //State = RequestState.Finished;
509 //finalResponse = ftpResponse;
510 asyncResult.SetCompleted (false, ftpResponse);
512 catch (Exception e) {
513 State = RequestState.Error;
514 SetCompleteWithError (e);
519 FtpStatus status = GetResponseStatus ();
521 ftpResponse.UpdateStatus (status);
523 if (ftpResponse.IsFinal ()) {
524 State = RequestState.Finished;
528 asyncResult.SetCompleted (false, ftpResponse);
535 FtpStatus status = SendCommand (TypeCommand, DataType);
536 if ((int) status.StatusCode < 200 || (int) status.StatusCode >= 300)
537 throw CreateExceptionFromResponse (status);
541 string GetRemoteFolderPath (Uri uri)
544 string local_path = Uri.UnescapeDataString (uri.LocalPath);
545 if (initial_path == null || initial_path == "/") {
548 if (local_path [0] == '/')
549 local_path = local_path.Substring (1);
551 Uri initial = new Uri ("ftp://dummy-host" + initial_path);
552 result = new Uri (initial, local_path).LocalPath;
555 int last = result.LastIndexOf ('/');
559 return result.Substring (0, last + 1);
562 void CWDAndSetFileName (Uri uri)
564 string remote_folder = GetRemoteFolderPath (uri);
566 if (remote_folder != null) {
567 status = SendCommand (ChangeDir, remote_folder);
568 if ((int) status.StatusCode < 200 || (int) status.StatusCode >= 300)
569 throw CreateExceptionFromResponse (status);
571 int last = uri.LocalPath.LastIndexOf ('/');
573 file_name = Uri.UnescapeDataString (uri.LocalPath.Substring (last + 1));
578 void ProcessMethod ()
580 State = RequestState.Connecting;
584 OpenControlConnection ();
585 CWDAndSetFileName (requestUri);
589 // Open data connection and receive data
590 case WebRequestMethods.Ftp.DownloadFile:
591 case WebRequestMethods.Ftp.ListDirectory:
592 case WebRequestMethods.Ftp.ListDirectoryDetails:
595 // Open data connection and send data
596 case WebRequestMethods.Ftp.AppendFile:
597 case WebRequestMethods.Ftp.UploadFile:
598 case WebRequestMethods.Ftp.UploadFileWithUniqueName:
601 // Get info from control connection
602 case WebRequestMethods.Ftp.GetFileSize:
603 case WebRequestMethods.Ftp.GetDateTimestamp:
604 case WebRequestMethods.Ftp.PrintWorkingDirectory:
605 case WebRequestMethods.Ftp.MakeDirectory:
606 case WebRequestMethods.Ftp.Rename:
607 case WebRequestMethods.Ftp.DeleteFile:
608 ProcessSimpleMethod ();
610 default: // What to do here?
611 throw new Exception (String.Format ("Support for command {0} not implemented yet", method));
617 private void CloseControlConnection () {
618 SendCommand (QuitCommand);
619 controlStream.Close ();
622 private void CloseDataConnection () {
623 if(dataSocket != null)
627 private void CloseConnection () {
628 CloseControlConnection ();
629 CloseDataConnection ();
632 void ProcessSimpleMethod ()
634 State = RequestState.TransferInProgress;
638 if (method == WebRequestMethods.Ftp.PrintWorkingDirectory)
641 if (method == WebRequestMethods.Ftp.Rename)
642 method = RenameFromCommand;
644 status = SendCommand (method, file_name);
646 ftpResponse.Stream = Stream.Null;
648 string desc = status.StatusDescription;
651 case WebRequestMethods.Ftp.GetFileSize: {
652 if (status.StatusCode != FtpStatusCode.FileStatus)
653 throw CreateExceptionFromResponse (status);
657 for (i = 4, len = 0; i < desc.Length && Char.IsDigit (desc [i]); i++, len++)
661 throw new WebException ("Bad format for server response in " + method);
663 if (!Int64.TryParse (desc.Substring (4, len), out size))
664 throw new WebException ("Bad format for server response in " + method);
666 ftpResponse.contentLength = size;
669 case WebRequestMethods.Ftp.GetDateTimestamp:
670 if (status.StatusCode != FtpStatusCode.FileStatus)
671 throw CreateExceptionFromResponse (status);
672 ftpResponse.LastModified = DateTime.ParseExact (desc.Substring (4), "yyyyMMddHHmmss", null);
674 case WebRequestMethods.Ftp.MakeDirectory:
675 if (status.StatusCode != FtpStatusCode.PathnameCreated)
676 throw CreateExceptionFromResponse (status);
679 method = WebRequestMethods.Ftp.PrintWorkingDirectory;
681 if (status.StatusCode != FtpStatusCode.FileActionOK)
682 throw CreateExceptionFromResponse (status);
684 status = SendCommand (method);
686 if (status.StatusCode != FtpStatusCode.PathnameCreated)
687 throw CreateExceptionFromResponse (status);
689 case RenameFromCommand:
690 method = WebRequestMethods.Ftp.Rename;
691 if (status.StatusCode != FtpStatusCode.FileCommandPending)
692 throw CreateExceptionFromResponse (status);
693 // Pass an empty string if RenameTo wasn't specified
694 status = SendCommand (RenameToCommand, renameTo != null ? renameTo : String.Empty);
695 if (status.StatusCode != FtpStatusCode.FileActionOK)
696 throw CreateExceptionFromResponse (status);
698 case WebRequestMethods.Ftp.DeleteFile:
699 if (status.StatusCode != FtpStatusCode.FileActionOK) {
700 throw CreateExceptionFromResponse (status);
705 State = RequestState.Finished;
710 State = RequestState.OpeningData;
712 OpenDataConnection ();
714 State = RequestState.TransferInProgress;
715 requestStream = new FtpDataStream (this, dataSocket, false);
716 asyncResult.Stream = requestStream;
721 State = RequestState.OpeningData;
723 OpenDataConnection ();
725 State = RequestState.TransferInProgress;
726 ftpResponse.Stream = new FtpDataStream (this, dataSocket, true);
729 void CheckRequestStarted ()
731 if (State != RequestState.Before)
732 throw new InvalidOperationException ("There is a request currently in progress");
735 void OpenControlConnection ()
737 Exception exception = null;
739 foreach (IPAddress address in hostEntry.AddressList) {
740 sock = new Socket (address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
742 IPEndPoint remote = new IPEndPoint (address, requestUri.Port);
744 if (!ServicePoint.CallEndPointDelegate (sock, remote)) {
749 sock.Connect (remote);
750 localEndPoint = (IPEndPoint) sock.LocalEndPoint;
752 } catch (SocketException exc) {
760 // Couldn't connect to any address
762 throw new WebException ("Unable to connect to remote server", exception,
763 WebExceptionStatus.UnknownError, ftpResponse);
765 controlStream = new NetworkStream (sock);
766 controlReader = new StreamReader (controlStream, Encoding.ASCII);
768 State = RequestState.Authenticating;
771 FtpStatus status = SendCommand ("OPTS", "utf8", "on");
772 // ignore status for OPTS
773 status = SendCommand (WebRequestMethods.Ftp.PrintWorkingDirectory);
774 initial_path = GetInitialPath (status);
777 static string GetInitialPath (FtpStatus status)
779 int s = (int) status.StatusCode;
780 if (s < 200 || s > 300 || status.StatusDescription.Length <= 4)
781 throw new WebException ("Error getting current directory: " + status.StatusDescription, null,
782 WebExceptionStatus.UnknownError, null);
784 string msg = status.StatusDescription.Substring (4);
785 if (msg [0] == '"') {
786 int next_quote = msg.IndexOf ('\"', 1);
787 if (next_quote == -1)
788 throw new WebException ("Error getting current directory: PWD -> " + status.StatusDescription, null,
789 WebExceptionStatus.UnknownError, null);
791 msg = msg.Substring (1, next_quote - 1);
794 if (!msg.EndsWith ("/"))
799 // Probably we could do better having here a regex
800 Socket SetupPassiveConnection (string statusDescription)
802 // Current response string
803 string response = statusDescription;
804 if (response.Length < 4)
805 throw new WebException ("Cannot open passive data connection");
807 // Look for first digit after code
809 for (i = 3; i < response.Length && !Char.IsDigit (response [i]); i++)
811 if (i >= response.Length)
812 throw new WebException ("Cannot open passive data connection");
815 string [] digits = response.Substring (i).Split (new char [] {','}, 6);
816 if (digits.Length != 6)
817 throw new WebException ("Cannot open passive data connection");
819 // Clean non-digits at the end of last element
821 for (j = digits [5].Length - 1; j >= 0 && !Char.IsDigit (digits [5][j]); j--)
824 throw new WebException ("Cannot open passive data connection");
826 digits [5] = digits [5].Substring (0, j + 1);
830 ip = IPAddress.Parse (String.Join (".", digits, 0, 4));
831 } catch (FormatException) {
832 throw new WebException ("Cannot open passive data connection");
837 if (!Int32.TryParse (digits [4], out p1) || !Int32.TryParse (digits [5], out p2))
838 throw new WebException ("Cannot open passive data connection");
840 port = (p1 << 8) + p2; // p1 * 256 + p2
841 //port = p1 * 256 + p2;
842 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
843 throw new WebException ("Cannot open passive data connection");
845 IPEndPoint ep = new IPEndPoint (ip, port);
846 Socket sock = new Socket (ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
849 } catch (SocketException) {
851 throw new WebException ("Cannot open passive data connection");
857 Exception CreateExceptionFromResponse (FtpStatus status)
859 FtpWebResponse ftpResponse = new FtpWebResponse (this, requestUri, method, status);
861 WebException exc = new WebException ("Server returned an error: " + status.StatusDescription,
862 null, WebExceptionStatus.ProtocolError, ftpResponse);
866 // Here we could also get a server error, so be cautious
867 internal void SetTransferCompleted ()
872 State = RequestState.Finished;
873 FtpStatus status = GetResponseStatus ();
874 ftpResponse.UpdateStatus (status);
879 internal void OperationCompleted ()
885 void SetCompleteWithError (Exception exc)
887 if (asyncResult != null) {
888 asyncResult.SetCompleted (false, exc);
892 Socket InitDataConnection ()
897 status = SendCommand (PassiveCommand);
898 if (status.StatusCode != FtpStatusCode.EnteringPassive) {
899 throw CreateExceptionFromResponse (status);
902 return SetupPassiveConnection (status.StatusDescription);
905 // Open a socket to listen the server's connection
906 Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
908 sock.Bind (new IPEndPoint (localEndPoint.Address, 0));
909 sock.Listen (1); // We only expect a connection from server
911 } catch (SocketException e) {
914 throw new WebException ("Couldn't open listening socket on client", e);
917 IPEndPoint ep = (IPEndPoint) sock.LocalEndPoint;
918 string ipString = ep.Address.ToString ().Replace ('.', ',');
919 int h1 = ep.Port >> 8; // ep.Port / 256
920 int h2 = ep.Port % 256;
922 string portParam = ipString + "," + h1 + "," + h2;
923 status = SendCommand (PortCommand, portParam);
925 if (status.StatusCode != FtpStatusCode.CommandOK) {
927 throw (CreateExceptionFromResponse (status));
933 void OpenDataConnection ()
937 Socket s = InitDataConnection ();
939 // Handle content offset
941 status = SendCommand (RestCommand, offset.ToString ());
942 if (status.StatusCode != FtpStatusCode.FileCommandPending)
943 throw CreateExceptionFromResponse (status);
946 if (method != WebRequestMethods.Ftp.ListDirectory && method != WebRequestMethods.Ftp.ListDirectoryDetails &&
947 method != WebRequestMethods.Ftp.UploadFileWithUniqueName) {
948 status = SendCommand (method, file_name);
950 status = SendCommand (method);
953 if (status.StatusCode != FtpStatusCode.OpeningData && status.StatusCode != FtpStatusCode.DataAlreadyOpen)
954 throw CreateExceptionFromResponse (status);
961 // Active connection (use Socket.Blocking to true)
962 Socket incoming = null;
964 incoming = s.Accept ();
966 catch (SocketException) {
968 if (incoming != null)
971 throw new ProtocolViolationException ("Server commited a protocol violation.");
975 dataSocket = incoming;
979 InitiateSecureConnection (ref controlStream);
980 controlReader = new StreamReader (controlStream, Encoding.ASCII);
983 ftpResponse.UpdateStatus (status);
988 string username = null;
989 string password = null;
990 string domain = null;
992 if (credentials != null) {
993 username = credentials.UserName;
994 password = credentials.Password;
995 domain = credentials.Domain;
998 if (username == null)
999 username = "anonymous";
1000 if (password == null)
1001 password = "@anonymous";
1002 if (!string.IsNullOrEmpty (domain))
1003 username = domain + '\\' + username;
1005 // Connect to server and get banner message
1006 FtpStatus status = GetResponseStatus ();
1007 ftpResponse.BannerMessage = status.StatusDescription;
1010 InitiateSecureConnection (ref controlStream);
1011 controlReader = new StreamReader (controlStream, Encoding.ASCII);
1014 if (status.StatusCode != FtpStatusCode.SendUserCommand)
1015 throw CreateExceptionFromResponse (status);
1017 status = SendCommand (UserCommand, username);
1019 switch (status.StatusCode) {
1020 case FtpStatusCode.SendPasswordCommand:
1021 status = SendCommand (PasswordCommand, password);
1022 if (status.StatusCode != FtpStatusCode.LoggedInProceed)
1023 throw CreateExceptionFromResponse (status);
1025 case FtpStatusCode.LoggedInProceed:
1028 throw CreateExceptionFromResponse (status);
1031 ftpResponse.WelcomeMessage = status.StatusDescription;
1032 ftpResponse.UpdateStatus (status);
1035 FtpStatus SendCommand (string command, params string [] parameters) {
1036 return SendCommand (true, command, parameters);
1039 FtpStatus SendCommand (bool waitResponse, string command, params string [] parameters)
1042 string commandString = command;
1043 if (parameters.Length > 0)
1044 commandString += " " + String.Join (" ", parameters);
1046 commandString += EOL;
1047 cmd = Encoding.ASCII.GetBytes (commandString);
1049 controlStream.Write (cmd, 0, cmd.Length);
1050 } catch (IOException) {
1051 //controlStream.Close ();
1052 return new FtpStatus(FtpStatusCode.ServiceNotAvailable, "Write failed");
1058 FtpStatus result = GetResponseStatus ();
1059 if (ftpResponse != null)
1060 ftpResponse.UpdateStatus (result);
1064 internal static FtpStatus ServiceNotAvailable ()
1066 return new FtpStatus (FtpStatusCode.ServiceNotAvailable, Locale.GetText ("Invalid response from server"));
1069 internal FtpStatus GetResponseStatus ()
1072 string response = null;
1075 response = controlReader.ReadLine ();
1076 } catch (IOException) {
1079 if (response == null || response.Length < 3)
1080 return ServiceNotAvailable ();
1083 if (!Int32.TryParse (response.Substring (0, 3), out code))
1084 return ServiceNotAvailable ();
1086 if (response.Length > 3 && response [3] == '-'){
1088 string find = code.ToString() + ' ';
1091 line = controlReader.ReadLine();
1092 } catch (IOException) {
1095 return ServiceNotAvailable ();
1097 response += Environment.NewLine + line;
1099 if (line.StartsWith(find, StringComparison.Ordinal))
1103 return new FtpStatus ((FtpStatusCode) code, response);
1107 private void InitiateSecureConnection (ref NetworkStream stream) {
1108 FtpStatus status = SendCommand (AuthCommand, "TLS");
1110 if (status.StatusCode != FtpStatusCode.ServerWantsSecureSession) {
1111 throw CreateExceptionFromResponse (status);
1114 ChangeToSSLSocket (ref stream);
1117 internal static bool ChangeToSSLSocket (ref NetworkStream stream) {
1119 stream.ChangeToSSLSocket ();
1122 throw new NotImplementedException ();
1126 bool InFinalState () {
1127 return (State == RequestState.Aborted || State == RequestState.Error || State == RequestState.Finished);
1130 bool InProgress () {
1131 return (State != RequestState.Before && !InFinalState ());
1134 internal void CheckIfAborted () {
1135 if (State == RequestState.Aborted)
1136 throw new WebException ("Request aborted", WebExceptionStatus.RequestCanceled);
1139 void CheckFinalState () {
1140 if (InFinalState ())
1141 throw new InvalidOperationException ("Cannot change final state");