2 // FtpWebRequestTest.cs - NUnit Test Cases for System.Net.FtpWebRequest
5 // Carlos Alberto Cortez <calberto.cortez@gmail.com>
6 // Gonzalo Paniagua Javier <gonzalo@novell.com>
8 // Copyright (c) 2006,2007,2008 Novell, Inc. (http://www.novell.com)
10 using NUnit.Framework;
12 using System.Collections.Generic;
15 using System.Net.Sockets;
17 using System.Threading;
19 namespace MonoTests.System.Net
22 public class FtpWebRequestTest
24 FtpWebRequest defaultRequest;
26 private string _tempDirectory;
27 private string _tempFile;
32 _tempDirectory = Path.Combine (Path.GetTempPath (), "MonoTests.System.Net.FileWebRequestTest");
33 _tempFile = Path.Combine (_tempDirectory, "FtpWebRequestTest.tmp");
34 if (!Directory.Exists (_tempDirectory)) {
35 Directory.CreateDirectory (_tempDirectory);
37 // ensure no files are left over from previous runs
38 string [] files = Directory.GetFiles (_tempDirectory, "*");
39 foreach (string file in files)
45 public void TearDown ()
47 if (Directory.Exists (_tempDirectory))
48 Directory.Delete (_tempDirectory, true);
54 defaultRequest = (FtpWebRequest) WebRequest.Create ("ftp://www.contoso.com");
58 public void ContentLength ()
61 long l = defaultRequest.ContentLength;
62 } catch (NotSupportedException) {
63 Assert.Fail ("#1"); // Not overriden
67 defaultRequest.ContentLength = 2;
68 } catch (NotSupportedException) {
69 Assert.Fail ("#2"); // Not overriden
74 public void ContentType ()
77 string t = defaultRequest.ContentType;
79 } catch (NotSupportedException) {
83 defaultRequest.ContentType = String.Empty;
85 } catch (NotSupportedException) {
90 public void ContentOffset ()
93 defaultRequest.ContentOffset = -2;
95 } catch (ArgumentOutOfRangeException) {
100 public void Credentials ()
103 defaultRequest.Credentials = null;
105 } catch (ArgumentNullException) {
111 public void Method ()
114 defaultRequest.Method = null;
116 } catch (ArgumentNullException) {
120 defaultRequest.Method = String.Empty;
122 } catch (ArgumentException) {
126 defaultRequest.Method = "WrongValue";
128 } catch (ArgumentException) {
133 public void PreAuthenticate ()
136 bool p = defaultRequest.PreAuthenticate;
138 } catch (NotSupportedException) {
142 defaultRequest.PreAuthenticate = true;
143 } catch (NotSupportedException) {
148 public void ReadWriteTimeout ()
151 defaultRequest.ReadWriteTimeout = -2;
153 } catch (ArgumentOutOfRangeException) {
158 public void Timeout ()
161 defaultRequest.Timeout = -2;
163 } catch (ArgumentOutOfRangeException) {
168 public void DefaultValues ()
170 FtpWebRequest request = (FtpWebRequest) WebRequest.Create ("ftp://www.contoso.com");
172 Assert.AreEqual (0, request.ContentOffset, "ContentOffset");
173 Assert.AreEqual (false, request.EnableSsl, "EnableSsl");
174 // FIXME: Disabled this one by now. KeepAlive is not well supported.
175 // Assert.AreEqual (true, request.KeepAlive, "KeepAlive");
176 Assert.AreEqual (WebRequestMethods.Ftp.DownloadFile, request.Method, "#1");
177 Assert.AreEqual (300000, request.ReadWriteTimeout, "ReadWriteTimeout");
178 Assert.IsNull (request.RenameTo, "RenameTo");
179 Assert.AreEqual (true, request.UseBinary, "UseBinary");
180 Assert.AreEqual (100000, request.Timeout, "Timeout");
181 Assert.AreEqual (true, request.UsePassive, "UsePassive");
185 public void RenameTo ()
188 defaultRequest.RenameTo = null;
190 } catch (ArgumentException) {
194 defaultRequest.RenameTo = String.Empty;
196 } catch (ArgumentException) {
201 public void UploadFile1 ()
203 ServerPut sp = new ServerPut ();
205 string uri = String.Format ("ftp://{0}:{1}/uploads/file.txt", sp.IPAddress, sp.Port);
207 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
208 ftp.KeepAlive = false;
210 ftp.Method = WebRequestMethods.Ftp.UploadFile;
211 ftp.ContentLength = 10;
212 ftp.UseBinary = true;
213 Stream stream = ftp.GetRequestStream ();
214 for (int i = 0; i < 10; i++)
215 stream.WriteByte ((byte)i);
217 FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ();
218 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "UP#01");
219 Assert.AreEqual (10, sp.result.Count, "UP#02");
221 } catch (Exception) {
222 if (!String.IsNullOrEmpty (sp.Where))
223 throw new Exception (sp.Where);
231 public void UploadFile_WebClient ()
233 ServerPut sp = new ServerPut ();
234 File.WriteAllText (_tempFile, "0123456789");
237 using (WebClient m_WebClient = new WebClient())
239 string uri = String.Format ("ftp://{0}:{1}/uploads/file.txt", sp.IPAddress, sp.Port);
241 m_WebClient.UploadFile(uri, _tempFile);
243 Assert.AreEqual (10, sp.result.Count, "WebClient/Ftp#01");
249 public void DownloadFile1 ()
251 DownloadFile (new ServerDownload ());
254 void DownloadFile (ServerDownload sp)
257 string uri = String.Format ("ftp://{0}:{1}/file.txt", sp.IPAddress, sp.Port);
259 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
260 ftp.KeepAlive = false;
262 ftp.Method = WebRequestMethods.Ftp.DownloadFile;
263 ftp.UseBinary = true;
264 FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ();
265 Assert.IsTrue ((int) response.StatusCode >= 100 && (int) response.StatusCode < 200, "DL#01");
266 using (Stream st = response.GetResponseStream ()) {
268 // This should be "220 Bye" or similar (no KeepAlive)
269 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DL#02");
271 } catch (Exception) {
272 if (!String.IsNullOrEmpty (sp.Where))
273 throw new Exception (sp.Where);
281 public void DownloadFile2 ()
283 // Some embedded FTP servers in Industrial Automation Hardware report
284 // the PWD using backslashes, but allow forward slashes for CWD.
285 DownloadFile (new ServerDownload (@"\Users\someuser", "/Users/someuser/"));
289 public void DeleteFile1 ()
291 ServerDeleteFile sp = new ServerDeleteFile ();
293 string uri = String.Format ("ftp://{0}:{1}/file.txt", sp.IPAddress, sp.Port);
295 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
296 Console.WriteLine (ftp.RequestUri);
297 ftp.KeepAlive = false;
299 ftp.Method = WebRequestMethods.Ftp.DeleteFile;
300 ftp.UseBinary = true;
301 FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ();
302 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DF#01");
304 } catch (Exception e) {
305 Console.WriteLine (e);
306 if (!String.IsNullOrEmpty (sp.Where))
307 throw new Exception (sp.Where);
315 public void ListDirectory1 ()
317 ServerListDirectory sp = new ServerListDirectory ();
319 string uri = String.Format ("ftp://{0}:{1}/somedir/", sp.IPAddress, sp.Port);
321 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
322 Console.WriteLine (ftp.RequestUri);
323 ftp.KeepAlive = false;
325 ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
326 ftp.UseBinary = true;
327 using (FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ()) {
328 StreamReader reader = new StreamReader (response.GetResponseStream ());
329 string result = reader.ReadToEnd ();
330 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DF#01");
332 } catch (Exception e) {
333 Console.WriteLine (e);
334 if (!String.IsNullOrEmpty (sp.Where))
335 throw new Exception (sp.Where);
342 class ServerListDirectory : FtpServer {
343 protected override void Run ()
345 Socket client = control.Accept ();
346 NetworkStream ns = new NetworkStream (client, false);
347 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
348 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
349 if (!DoAnonymousLogin (writer, reader)) {
354 if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/somedir/")) {
359 string str = reader.ReadLine ();
366 IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint;
367 byte [] addr_bytes = end_data.Address.GetAddressBytes ();
368 byte [] port = new byte [2];
369 port[0] = (byte) ((end_data.Port >> 8) & 255);
370 port[1] = (byte) (end_data.Port & 255);
371 StringBuilder sb = new StringBuilder ("227 Passive (");
372 foreach (byte b in addr_bytes) {
373 sb.AppendFormat ("{0},", b);
375 sb.AppendFormat ("{0},", port [0]);
376 sb.AppendFormat ("{0})", port [1]);
377 writer.WriteLine (sb.ToString ());
380 str = reader.ReadLine ();
382 Where = "LIST - '" + str + "'";
386 writer.WriteLine ("150 Here comes the directory listing");
389 Socket data_cnc = data.Accept ();
390 byte [] dontcare = Encoding.ASCII.GetBytes ("drwxr-xr-x 2 ftp ftp 4096 Oct 27 20:17 tests");
391 data_cnc.Send (dontcare, 1, SocketFlags.None);
393 writer.WriteLine ("226 Directory send Ok");
395 if (!EndConversation (writer, reader)) {
403 class ServerDeleteFile : FtpServer {
404 protected override void Run ()
406 Socket client = control.Accept ();
407 NetworkStream ns = new NetworkStream (client, false);
408 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
409 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
410 if (!DoAnonymousLogin (writer, reader)) {
415 if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/")) {
420 string str = reader.ReadLine ();
421 if (str.Trim () != "DELE file.txt") {
422 Where = "DELE - " + str;
426 writer.WriteLine ("250 Delete operation successful");
428 if (!EndConversation (writer, reader)) {
436 class ServerDownload : FtpServer {
440 public ServerDownload ()
445 public ServerDownload (string pwd, string cwd)
447 Pwd = pwd ?? "/home/someuser";
448 Cwd = cwd ?? "/home/someuser/";
451 protected override void Run ()
453 Socket client = control.Accept ();
454 NetworkStream ns = new NetworkStream (client, false);
455 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
456 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
457 if (!DoAnonymousLogin (writer, reader)) {
462 if (!DoInitialDialog (writer, reader, Pwd, Cwd)) {
467 string str = reader.ReadLine ();
474 IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint;
475 byte [] addr_bytes = end_data.Address.GetAddressBytes ();
476 byte [] port = new byte [2];
477 port[0] = (byte) ((end_data.Port >> 8) & 255);
478 port[1] = (byte) (end_data.Port & 255);
479 StringBuilder sb = new StringBuilder ("227 Passive (");
480 foreach (byte b in addr_bytes) {
481 sb.AppendFormat ("{0},", b);
483 sb.AppendFormat ("{0},", port [0]);
484 sb.AppendFormat ("{0})", port [1]);
485 writer.WriteLine (sb.ToString ());
488 str = reader.ReadLine ();
489 if (str != "RETR file.txt") {
490 Where = "RETR - " + str;
494 writer.WriteLine ("150 Opening BINARY mode data connection for blah (n bytes)");
497 Socket data_cnc = data.Accept ();
498 byte [] dontcare = new byte [1];
499 data_cnc.Receive (dontcare, 1, SocketFlags.None);
501 writer.WriteLine ("226 File send Ok");
503 if (!EndConversation (writer, reader)) {
511 class ServerPut : FtpServer {
512 public List<byte> result = new List<byte> ();
514 protected override void Run ()
516 Socket client = control.Accept ();
517 NetworkStream ns = new NetworkStream (client, false);
518 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
519 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
520 if (!DoAnonymousLogin (writer, reader)) {
525 if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/uploads/")) {
530 string str = reader.ReadLine ();
537 IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint;
538 byte [] addr_bytes = end_data.Address.GetAddressBytes ();
539 byte [] port = new byte [2];
540 port[0] = (byte) ((end_data.Port >> 8) & 255);
541 port[1] = (byte) (end_data.Port & 255);
542 StringBuilder sb = new StringBuilder ("227 Passive (");
543 foreach (byte b in addr_bytes) {
544 sb.AppendFormat ("{0},", b);
546 sb.AppendFormat ("{0},", port [0]);
547 sb.AppendFormat ("{0})", port [1]);
548 writer.WriteLine (sb.ToString ());
551 str = reader.ReadLine ();
552 if (str != "STOR file.txt") {
553 Where = "STOR - " + str;
557 writer.WriteLine ("150 Ok to send data");
560 Socket data_cnc = data.Accept ();
561 var datastr = new NetworkStream (data_cnc, false);
563 while ((ch = datastr.ReadByte ()) != -1){
564 result.Add ((byte)ch);
568 writer.WriteLine ("226 File received Ok");
570 if (!EndConversation (writer, reader)) {
578 abstract class FtpServer {
579 protected Socket control;
580 protected Socket data;
581 protected ManualResetEvent evt;
582 public string Where = "";
586 control = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
587 control.Bind (new IPEndPoint (IPAddress.Loopback, 0));
589 data = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
590 data.Bind (new IPEndPoint (IPAddress.Loopback, 0));
596 evt = new ManualResetEvent (false);
597 Thread th = new Thread (new ThreadStart (Run));
608 // PWD, CWD and TYPE I (type could be moved out of here)
609 protected bool DoInitialDialog (StreamWriter writer, StreamReader reader, string pwd, string cwd)
611 string str = reader.ReadLine ();
612 if (!str.StartsWith ("OPTS utf8 on")) {
613 Where = "OPTS utf8 - " + str;
616 writer.WriteLine ("200 Always in UTF8 mode"); // vsftpd
618 str = reader.ReadLine ();
619 if (!str.StartsWith ("PWD")) {
620 Where = "PWD - " + str;
623 writer.WriteLine ("257 \"{0}\"", pwd);
625 str = reader.ReadLine ();
626 if (str != ("CWD " + cwd)) {
627 Where = "CWD - " + str;
630 writer.WriteLine ("250 Directory changed");
632 str = reader.ReadLine ();
633 if (str != ("TYPE I")) {
634 Where = "TYPE - " + str;
637 writer.WriteLine ("200 Switching to binary mode");
642 protected bool EndConversation (StreamWriter writer, StreamReader reader)
644 string str = reader.ReadLine ();
649 writer.WriteLine ("220 Bye");
655 protected bool DoAnonymousLogin (StreamWriter writer, StreamReader reader)
657 writer.WriteLine ("220 Welcome to the jungle");
659 string str = reader.ReadLine ();
660 if (!str.StartsWith ("USER ")) {
664 writer.WriteLine ("331 Say 'Mellon'");
666 str = reader.ReadLine ();
667 if (!str.StartsWith ("PASS ")) {
671 writer.WriteLine ("230 Logged in");
676 public IPAddress IPAddress {
677 get { return ((IPEndPoint) control.LocalEndPoint).Address; }
681 get { return ((IPEndPoint) control.LocalEndPoint).Port; }
684 protected abstract void Run ();