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 public bool KeepAlive {
212 CheckRequestStarted ();
217 public override string Method {
222 CheckRequestStarted ();
224 throw new ArgumentNullException ("Method string cannot be null");
226 if (value.Length == 0 || Array.BinarySearch (supportedCommands, value) < 0)
227 throw new ArgumentException ("Method not supported", "value");
233 public override bool PreAuthenticate {
235 throw new NotSupportedException ();
238 throw new NotSupportedException ();
242 public override IWebProxy Proxy {
247 CheckRequestStarted ();
249 throw new ArgumentNullException ();
255 public int ReadWriteTimeout {
260 CheckRequestStarted ();
263 throw new ArgumentOutOfRangeException ();
269 public string RenameTo {
274 CheckRequestStarted ();
275 if (value == null || value.Length == 0)
276 throw new ArgumentException ("RenameTo value can't be null or empty", "RenameTo");
282 public override Uri RequestUri {
288 public ServicePoint ServicePoint {
290 return GetServicePoint ();
294 public bool UsePassive {
299 CheckRequestStarted ();
305 public override bool UseDefaultCredentials
308 throw GetMustImplement ();
311 throw GetMustImplement ();
315 public bool UseBinary {
319 CheckRequestStarted ();
324 public override int Timeout {
329 CheckRequestStarted ();
332 throw new ArgumentOutOfRangeException ();
340 return binary ? "I" : "A";
355 requestState = value;
360 public override void Abort () {
362 if (State == RequestState.TransferInProgress) {
363 /*FtpStatus status = */
364 SendCommand (false, AbortCommand);
367 if (!InFinalState ()) {
368 State = RequestState.Aborted;
369 ftpResponse = new FtpWebResponse (requestUri, method, FtpStatusCode.FileActionAborted, "Aborted by request");
374 public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state) {
375 if (asyncResult != null && !asyncResult.IsCompleted) {
376 throw new InvalidOperationException ("Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call is still in progress");
381 asyncResult = new FtpAsyncResult (callback, state);
385 asyncResult.SetCompleted (true, ftpResponse);
387 if (State == RequestState.Before)
388 State = RequestState.Scheduled;
390 Thread thread = new Thread (ProcessRequest);
398 public override WebResponse EndGetResponse (IAsyncResult asyncResult) {
399 if (asyncResult == null)
400 throw new ArgumentNullException ("AsyncResult cannot be null!");
402 if (!(asyncResult is FtpAsyncResult) || asyncResult != this.asyncResult)
403 throw new ArgumentException ("AsyncResult is from another request!");
405 FtpAsyncResult asyncFtpResult = (FtpAsyncResult) asyncResult;
406 if (!asyncFtpResult.WaitUntilComplete (timeout, false)) {
408 throw new WebException ("Transfer timed out.", WebExceptionStatus.Timeout);
415 if (asyncFtpResult.GotException)
416 throw asyncFtpResult.Exception;
418 return asyncFtpResult.Response;
421 public override WebResponse GetResponse () {
422 IAsyncResult asyncResult = BeginGetResponse (null, null);
423 return EndGetResponse (asyncResult);
426 public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) {
427 if (method != WebRequestMethods.Ftp.UploadFile && method != WebRequestMethods.Ftp.UploadFileWithUniqueName &&
428 method != WebRequestMethods.Ftp.AppendFile)
429 throw new ProtocolViolationException ();
434 if (State != RequestState.Before)
435 throw new InvalidOperationException ("Cannot re-call BeginGetRequestStream/BeginGetResponse while a previous call is still in progress");
437 State = RequestState.Scheduled;
440 asyncResult = new FtpAsyncResult (callback, state);
441 Thread thread = new Thread (ProcessRequest);
447 public override Stream EndGetRequestStream (IAsyncResult asyncResult) {
448 if (asyncResult == null)
449 throw new ArgumentNullException ("asyncResult");
451 if (!(asyncResult is FtpAsyncResult))
452 throw new ArgumentException ("asyncResult");
454 if (State == RequestState.Aborted) {
455 throw new WebException ("Request aborted", WebExceptionStatus.RequestCanceled);
458 if (asyncResult != this.asyncResult)
459 throw new ArgumentException ("AsyncResult is from another request!");
461 FtpAsyncResult res = (FtpAsyncResult) asyncResult;
463 if (!res.WaitUntilComplete (timeout, false)) {
465 throw new WebException ("Request timed out");
468 if (res.GotException)
474 public override Stream GetRequestStream () {
475 IAsyncResult asyncResult = BeginGetRequestStream (null, null);
476 return EndGetRequestStream (asyncResult);
479 ServicePoint GetServicePoint ()
481 if (servicePoint == null)
482 servicePoint = ServicePointManager.FindServicePoint (requestUri, proxy);
487 // Probably move some code of command connection here
491 hostEntry = GetServicePoint ().HostEntry;
493 if (hostEntry == null) {
494 ftpResponse.UpdateStatus (new FtpStatus(FtpStatusCode.ActionAbortedLocalProcessingError, "Cannot resolve server name"));
495 throw new WebException ("The remote server name could not be resolved: " + requestUri,
496 null, WebExceptionStatus.NameResolutionFailure, ftpResponse);
500 void ProcessRequest () {
502 if (State == RequestState.Scheduled) {
503 ftpResponse = new FtpWebResponse (requestUri, method, keepAlive);
507 //State = RequestState.Finished;
508 //finalResponse = ftpResponse;
509 asyncResult.SetCompleted (false, ftpResponse);
511 catch (Exception e) {
512 State = RequestState.Error;
513 SetCompleteWithError (e);
518 FtpStatus status = GetResponseStatus ();
520 ftpResponse.UpdateStatus (status);
522 if (ftpResponse.IsFinal ()) {
523 State = RequestState.Finished;
527 asyncResult.SetCompleted (false, ftpResponse);
534 FtpStatus status = SendCommand (TypeCommand, DataType);
535 if ((int) status.StatusCode < 200 || (int) status.StatusCode >= 300)
536 throw CreateExceptionFromResponse (status);
540 string GetRemoteFolderPath (Uri uri)
543 string local_path = Uri.UnescapeDataString (uri.LocalPath);
544 if (initial_path == null) {
547 if (local_path [0] == '/')
548 local_path = local_path.Substring (1);
549 Uri initial = new Uri (initial_path);
550 result = new Uri (initial, local_path).LocalPath;
553 int last = result.LastIndexOf ('/');
557 return result.Substring (0, last + 1);
560 void CWDAndSetFileName (Uri uri)
562 string remote_folder = GetRemoteFolderPath (uri);
564 if (remote_folder != null) {
565 status = SendCommand (ChangeDir, remote_folder);
566 if ((int) status.StatusCode < 200 || (int) status.StatusCode >= 300)
567 throw CreateExceptionFromResponse (status);
569 int last = uri.LocalPath.LastIndexOf ('/');
571 file_name = Uri.UnescapeDataString (uri.LocalPath.Substring (last + 1));
576 void ProcessMethod ()
578 State = RequestState.Connecting;
582 OpenControlConnection ();
583 CWDAndSetFileName (requestUri);
587 // Open data connection and receive data
588 case WebRequestMethods.Ftp.DownloadFile:
589 case WebRequestMethods.Ftp.ListDirectory:
590 case WebRequestMethods.Ftp.ListDirectoryDetails:
593 // Open data connection and send data
594 case WebRequestMethods.Ftp.AppendFile:
595 case WebRequestMethods.Ftp.UploadFile:
596 case WebRequestMethods.Ftp.UploadFileWithUniqueName:
599 // Get info from control connection
600 case WebRequestMethods.Ftp.GetFileSize:
601 case WebRequestMethods.Ftp.GetDateTimestamp:
602 case WebRequestMethods.Ftp.PrintWorkingDirectory:
603 case WebRequestMethods.Ftp.MakeDirectory:
604 case WebRequestMethods.Ftp.Rename:
605 case WebRequestMethods.Ftp.DeleteFile:
606 ProcessSimpleMethod ();
608 default: // What to do here?
609 throw new Exception (String.Format ("Support for command {0} not implemented yet", method));
615 private void CloseControlConnection () {
616 SendCommand (QuitCommand);
617 controlStream.Close ();
620 private void CloseDataConnection () {
621 if(dataSocket != null)
625 private void CloseConnection () {
626 CloseControlConnection ();
627 CloseDataConnection ();
630 void ProcessSimpleMethod ()
632 State = RequestState.TransferInProgress;
636 if (method == WebRequestMethods.Ftp.PrintWorkingDirectory)
639 if (method == WebRequestMethods.Ftp.Rename)
640 method = RenameFromCommand;
642 status = SendCommand (method, file_name);
644 ftpResponse.Stream = new EmptyStream ();
646 string desc = status.StatusDescription;
649 case WebRequestMethods.Ftp.GetFileSize: {
650 if (status.StatusCode != FtpStatusCode.FileStatus)
651 throw CreateExceptionFromResponse (status);
655 for (i = 4, len = 0; i < desc.Length && Char.IsDigit (desc [i]); i++, len++)
659 throw new WebException ("Bad format for server response in " + method);
661 if (!Int64.TryParse (desc.Substring (4, len), out size))
662 throw new WebException ("Bad format for server response in " + method);
664 ftpResponse.contentLength = size;
667 case WebRequestMethods.Ftp.GetDateTimestamp:
668 if (status.StatusCode != FtpStatusCode.FileStatus)
669 throw CreateExceptionFromResponse (status);
670 ftpResponse.LastModified = DateTime.ParseExact (desc.Substring (4), "yyyyMMddHHmmss", null);
672 case WebRequestMethods.Ftp.MakeDirectory:
673 if (status.StatusCode != FtpStatusCode.PathnameCreated)
674 throw CreateExceptionFromResponse (status);
677 method = WebRequestMethods.Ftp.PrintWorkingDirectory;
679 if (status.StatusCode != FtpStatusCode.FileActionOK)
680 throw CreateExceptionFromResponse (status);
682 status = SendCommand (method);
684 if (status.StatusCode != FtpStatusCode.PathnameCreated)
685 throw CreateExceptionFromResponse (status);
687 case RenameFromCommand:
688 method = WebRequestMethods.Ftp.Rename;
689 if (status.StatusCode != FtpStatusCode.FileCommandPending)
690 throw CreateExceptionFromResponse (status);
691 // Pass an empty string if RenameTo wasn't specified
692 status = SendCommand (RenameToCommand, renameTo != null ? renameTo : String.Empty);
693 if (status.StatusCode != FtpStatusCode.FileActionOK)
694 throw CreateExceptionFromResponse (status);
696 case WebRequestMethods.Ftp.DeleteFile:
697 if (status.StatusCode != FtpStatusCode.FileActionOK) {
698 throw CreateExceptionFromResponse (status);
703 State = RequestState.Finished;
708 State = RequestState.OpeningData;
710 OpenDataConnection ();
712 State = RequestState.TransferInProgress;
713 requestStream = new FtpDataStream (this, dataSocket, false);
714 asyncResult.Stream = requestStream;
719 State = RequestState.OpeningData;
721 // Handle content offset
723 FtpStatus status = SendCommand (RestCommand, offset.ToString ());
725 if (status.StatusCode != FtpStatusCode.FileCommandPending)
726 throw CreateExceptionFromResponse (status);
729 OpenDataConnection ();
731 State = RequestState.TransferInProgress;
732 ftpResponse.Stream = new FtpDataStream (this, dataSocket, true);
735 void CheckRequestStarted ()
737 if (State != RequestState.Before)
738 throw new InvalidOperationException ("There is a request currently in progress");
741 void OpenControlConnection ()
744 foreach (IPAddress address in hostEntry.AddressList) {
745 sock = new Socket (address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
747 IPEndPoint remote = new IPEndPoint (address, requestUri.Port);
749 if (!ServicePoint.CallEndPointDelegate (sock, remote)) {
754 sock.Connect (remote);
755 localEndPoint = (IPEndPoint) sock.LocalEndPoint;
757 } catch (SocketException) {
764 // Couldn't connect to any address
766 throw new WebException ("Unable to connect to remote server", null,
767 WebExceptionStatus.UnknownError, ftpResponse);
769 controlStream = new NetworkStream (sock);
770 controlReader = new StreamReader (controlStream, Encoding.ASCII);
772 State = RequestState.Authenticating;
775 FtpStatus status = SendCommand ("OPTS", "utf8", "on");
776 // ignore status for OPTS
777 status = SendCommand (WebRequestMethods.Ftp.PrintWorkingDirectory);
778 initial_path = GetInitialPath (status);
781 static string GetInitialPath (FtpStatus status)
783 int s = (int) status.StatusCode;
784 if (s < 200 || s > 300 || status.StatusDescription.Length <= 4)
785 throw new WebException ("Error getting current directory: " + status.StatusDescription, null,
786 WebExceptionStatus.UnknownError, null);
788 string msg = status.StatusDescription.Substring (4);
789 if (msg [0] == '"') {
790 int next_quote = msg.IndexOf ('\"', 1);
791 if (next_quote == -1)
792 throw new WebException ("Error getting current directory: PWD -> " + status.StatusDescription, null,
793 WebExceptionStatus.UnknownError, null);
795 msg = msg.Substring (1, next_quote - 1);
798 if (!msg.EndsWith ("/"))
803 // Probably we could do better having here a regex
804 Socket SetupPassiveConnection (string statusDescription)
806 // Current response string
807 string response = statusDescription;
808 if (response.Length < 4)
809 throw new WebException ("Cannot open passive data connection");
811 // Look for first digit after code
813 for (i = 3; i < response.Length && !Char.IsDigit (response [i]); i++)
815 if (i >= response.Length)
816 throw new WebException ("Cannot open passive data connection");
819 string [] digits = response.Substring (i).Split (new char [] {','}, 6);
820 if (digits.Length != 6)
821 throw new WebException ("Cannot open passive data connection");
823 // Clean non-digits at the end of last element
825 for (j = digits [5].Length - 1; j >= 0 && !Char.IsDigit (digits [5][j]); j--)
828 throw new WebException ("Cannot open passive data connection");
830 digits [5] = digits [5].Substring (0, j + 1);
834 ip = IPAddress.Parse (String.Join (".", digits, 0, 4));
835 } catch (FormatException) {
836 throw new WebException ("Cannot open passive data connection");
841 if (!Int32.TryParse (digits [4], out p1) || !Int32.TryParse (digits [5], out p2))
842 throw new WebException ("Cannot open passive data connection");
844 port = (p1 << 8) + p2; // p1 * 256 + p2
845 //port = p1 * 256 + p2;
846 if (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
847 throw new WebException ("Cannot open passive data connection");
849 IPEndPoint ep = new IPEndPoint (ip, port);
850 Socket sock = new Socket (ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
853 } catch (SocketException) {
855 throw new WebException ("Cannot open passive data connection");
861 Exception CreateExceptionFromResponse (FtpStatus status)
863 FtpWebResponse ftpResponse = new FtpWebResponse (requestUri, method, status);
865 WebException exc = new WebException ("Server returned an error: " + status.StatusDescription,
866 null, WebExceptionStatus.ProtocolError, ftpResponse);
870 // Here we could also get a server error, so be cautious
871 internal void SetTransferCompleted ()
876 State = RequestState.Finished;
877 FtpStatus status = GetResponseStatus ();
878 ftpResponse.UpdateStatus (status);
883 void SetCompleteWithError (Exception exc)
885 if (asyncResult != null) {
886 asyncResult.SetCompleted (false, exc);
890 Socket InitDataConnection ()
895 status = SendCommand (PassiveCommand);
896 if (status.StatusCode != FtpStatusCode.EnteringPassive) {
897 throw CreateExceptionFromResponse (status);
900 return SetupPassiveConnection (status.StatusDescription);
903 // Open a socket to listen the server's connection
904 Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
906 sock.Bind (new IPEndPoint (localEndPoint.Address, 0));
907 sock.Listen (1); // We only expect a connection from server
909 } catch (SocketException e) {
912 throw new WebException ("Couldn't open listening socket on client", e);
915 IPEndPoint ep = (IPEndPoint) sock.LocalEndPoint;
916 string ipString = ep.Address.ToString ().Replace ('.', ',');
917 int h1 = ep.Port >> 8; // ep.Port / 256
918 int h2 = ep.Port % 256;
920 string portParam = ipString + "," + h1 + "," + h2;
921 status = SendCommand (PortCommand, portParam);
923 if (status.StatusCode != FtpStatusCode.CommandOK) {
925 throw (CreateExceptionFromResponse (status));
931 void OpenDataConnection ()
935 Socket s = InitDataConnection ();
937 if (method != WebRequestMethods.Ftp.ListDirectory && method != WebRequestMethods.Ftp.ListDirectoryDetails &&
938 method != WebRequestMethods.Ftp.UploadFileWithUniqueName) {
939 status = SendCommand (method, file_name);
941 status = SendCommand (method);
944 if (status.StatusCode != FtpStatusCode.OpeningData && status.StatusCode != FtpStatusCode.DataAlreadyOpen)
945 throw CreateExceptionFromResponse (status);
952 // Active connection (use Socket.Blocking to true)
953 Socket incoming = null;
955 incoming = s.Accept ();
957 catch (SocketException) {
959 if (incoming != null)
962 throw new ProtocolViolationException ("Server commited a protocol violation.");
966 dataSocket = incoming;
970 InitiateSecureConnection (ref controlStream);
971 controlReader = new StreamReader (controlStream, Encoding.ASCII);
974 ftpResponse.UpdateStatus (status);
979 string username = null;
980 string password = null;
981 string domain = null;
983 if (credentials != null) {
984 username = credentials.UserName;
985 password = credentials.Password;
986 domain = credentials.Domain;
989 if (username == null)
990 username = "anonymous";
991 if (password == null)
992 password = "@anonymous";
993 if (!string.IsNullOrEmpty (domain))
994 username = domain + '\\' + username;
996 // Connect to server and get banner message
997 FtpStatus status = GetResponseStatus ();
998 ftpResponse.BannerMessage = status.StatusDescription;
1001 InitiateSecureConnection (ref controlStream);
1002 controlReader = new StreamReader (controlStream, Encoding.ASCII);
1005 if (status.StatusCode != FtpStatusCode.SendUserCommand)
1006 throw CreateExceptionFromResponse (status);
1008 status = SendCommand (UserCommand, username);
1010 switch (status.StatusCode) {
1011 case FtpStatusCode.SendPasswordCommand:
1012 status = SendCommand (PasswordCommand, password);
1013 if (status.StatusCode != FtpStatusCode.LoggedInProceed)
1014 throw CreateExceptionFromResponse (status);
1016 case FtpStatusCode.LoggedInProceed:
1019 throw CreateExceptionFromResponse (status);
1022 ftpResponse.WelcomeMessage = status.StatusDescription;
1023 ftpResponse.UpdateStatus (status);
1026 FtpStatus SendCommand (string command, params string [] parameters) {
1027 return SendCommand (true, command, parameters);
1030 FtpStatus SendCommand (bool waitResponse, string command, params string [] parameters)
1033 string commandString = command;
1034 if (parameters.Length > 0)
1035 commandString += " " + String.Join (" ", parameters);
1037 commandString += EOL;
1038 cmd = Encoding.ASCII.GetBytes (commandString);
1040 controlStream.Write (cmd, 0, cmd.Length);
1041 } catch (IOException) {
1042 //controlStream.Close ();
1043 return new FtpStatus(FtpStatusCode.ServiceNotAvailable, "Write failed");
1049 FtpStatus result = GetResponseStatus ();
1050 if (ftpResponse != null)
1051 ftpResponse.UpdateStatus (result);
1055 internal static FtpStatus ServiceNotAvailable ()
1057 return new FtpStatus (FtpStatusCode.ServiceNotAvailable, Locale.GetText ("Invalid response from server"));
1060 internal FtpStatus GetResponseStatus ()
1063 string response = null;
1066 response = controlReader.ReadLine ();
1067 } catch (IOException) {
1070 if (response == null || response.Length < 3)
1071 return ServiceNotAvailable ();
1074 if (!Int32.TryParse (response.Substring (0, 3), out code))
1075 return ServiceNotAvailable ();
1077 if (response [3] == '-'){
1079 string find = code.ToString() + ' ';
1082 line = controlReader.ReadLine();
1083 } catch (IOException) {
1086 return ServiceNotAvailable ();
1088 response += Environment.NewLine + line;
1090 if (line.StartsWith(find, StringComparison.Ordinal))
1094 return new FtpStatus ((FtpStatusCode) code, response);
1098 private void InitiateSecureConnection (ref NetworkStream stream) {
1099 FtpStatus status = SendCommand (AuthCommand, "TLS");
1101 if (status.StatusCode != FtpStatusCode.ServerWantsSecureSession) {
1102 throw CreateExceptionFromResponse (status);
1105 ChangeToSSLSocket (ref stream);
1108 internal static bool ChangeToSSLSocket (ref NetworkStream stream) {
1110 stream.ChangeToSSLSocket ();
1113 throw new NotImplementedException ();
1117 bool InFinalState () {
1118 return (State == RequestState.Aborted || State == RequestState.Error || State == RequestState.Finished);
1121 bool InProgress () {
1122 return (State != RequestState.Before && !InFinalState ());
1125 internal void CheckIfAborted () {
1126 if (State == RequestState.Aborted)
1127 throw new WebException ("Request aborted", WebExceptionStatus.RequestCanceled);
1130 void CheckFinalState () {
1131 if (InFinalState ())
1132 throw new InvalidOperationException ("Cannot change final state");
1135 class EmptyStream : MemoryStream
1137 internal EmptyStream ()
1138 : base (new byte [0], false) {