Merge pull request #1156 from felfert/master
[mono.git] / mcs / class / System / Test / System.Net / FtpWebRequestTest.cs
1 //
2 // FtpWebRequestTest.cs - NUnit Test Cases for System.Net.FtpWebRequest
3 //
4 // Authors:
5 //      Carlos Alberto Cortez <calberto.cortez@gmail.com>
6 //      Gonzalo Paniagua Javier <gonzalo@novell.com>
7 //
8 // Copyright (c) 2006,2007,2008 Novell, Inc. (http://www.novell.com)
9 //
10 using NUnit.Framework;
11 using System;
12 using System.IO;
13 using System.Net;
14 using System.Net.Sockets;
15 using System.Text;
16 using System.Threading;
17
18 namespace MonoTests.System.Net 
19 {
20         [TestFixture]
21         public class FtpWebRequestTest
22         {
23                 FtpWebRequest defaultRequest;
24                 
25                 [TestFixtureSetUp]
26                 public void Init ()
27                 {
28                         defaultRequest = (FtpWebRequest) WebRequest.Create ("ftp://www.contoso.com");
29                 }
30                 
31                 [Test]
32                 public void ContentLength ()
33                 {
34                         try {
35                                 long l = defaultRequest.ContentLength;
36                         } catch (NotSupportedException) {
37                                 Assert.Fail ("#1"); // Not overriden
38                         }
39
40                         try {
41                                 defaultRequest.ContentLength = 2;
42                         } catch (NotSupportedException) {
43                                 Assert.Fail ("#2"); // Not overriden
44                         }
45                 }
46
47                 [Test]
48                 public void ContentType ()
49                 {
50                         try {
51                                 string t = defaultRequest.ContentType;
52                                 Assert.Fail ("#1");
53                         } catch (NotSupportedException) {
54                         }
55
56                         try {
57                                 defaultRequest.ContentType = String.Empty;
58                                 Assert.Fail ("#2");
59                         } catch (NotSupportedException) {
60                         }
61                 }
62
63                 [Test]
64                 public void ContentOffset ()
65                 {
66                         try {
67                                 defaultRequest.ContentOffset = -2;
68                                 Assert.Fail ("#1");
69                         } catch (ArgumentOutOfRangeException) {
70                         }
71                 }
72
73                 [Test]
74                 public void Credentials ()
75                 {
76                         try {
77                                 defaultRequest.Credentials = null;
78                                 Assert.Fail ("#1");
79                         } catch (ArgumentNullException) {
80                         }
81
82                 }
83
84                 [Test]
85                 public void Method ()
86                 {
87                         try {
88                                 defaultRequest.Method = null;
89                                 Assert.Fail ("#1");
90                         } catch (ArgumentNullException) {
91                         }
92
93                         try {
94                                 defaultRequest.Method = String.Empty;
95                                 Assert.Fail ("#2");
96                         } catch (ArgumentException) {
97                         }
98
99                         try {
100                                 defaultRequest.Method = "WrongValue";
101                                 Assert.Fail ("#3");
102                         } catch (ArgumentException) {
103                         }
104                 }
105
106                 [Test]
107                 public void PreAuthenticate ()
108                 {
109                         try {
110                                 bool p = defaultRequest.PreAuthenticate;
111                                 Assert.Fail ("#1");
112                         } catch (NotSupportedException) {
113                         }
114
115                         try {
116                                 defaultRequest.PreAuthenticate = true;
117                         } catch (NotSupportedException) {
118                         }
119                 }
120
121                 [Test]
122                 public void ReadWriteTimeout ()
123                 {
124                         try {
125                                 defaultRequest.ReadWriteTimeout = -2;
126                                 Assert.Fail ("#2");
127                         } catch (ArgumentOutOfRangeException) {
128                         }
129                 }
130
131                 [Test]
132                 public void Timeout ()
133                 {
134                         try {
135                                 defaultRequest.Timeout = -2;
136                                 Assert.Fail ("#2");
137                         } catch (ArgumentOutOfRangeException) {
138                         }
139                 }
140                 
141                 [Test]
142                 public void DefaultValues ()
143                 {
144                         FtpWebRequest request = (FtpWebRequest) WebRequest.Create ("ftp://www.contoso.com");
145                         
146                         Assert.AreEqual (0, request.ContentOffset, "ContentOffset");
147                         Assert.AreEqual (false, request.EnableSsl, "EnableSsl");
148                         // FIXME: Disabled this one by now. KeepAlive is not well supported.
149                         // Assert.AreEqual (true, request.KeepAlive, "KeepAlive");
150                         Assert.AreEqual (WebRequestMethods.Ftp.DownloadFile, request.Method, "#1");
151                         Assert.AreEqual (300000, request.ReadWriteTimeout, "ReadWriteTimeout");
152                         Assert.IsNull (request.RenameTo, "RenameTo");
153                         Assert.AreEqual (true, request.UseBinary, "UseBinary");
154                         Assert.AreEqual (100000, request.Timeout, "Timeout");
155                         Assert.AreEqual (true, request.UsePassive, "UsePassive");
156                 }
157
158                 [Test]
159                 public void RenameTo ()
160                 {
161                         try {
162                                 defaultRequest.RenameTo = null;
163                                 Assert.Fail ("#1");
164                         } catch (ArgumentException) {
165                         }
166
167                         try {
168                                 defaultRequest.RenameTo = String.Empty;
169                                 Assert.Fail ("#2");
170                         } catch (ArgumentException) {
171                         }
172                 }
173
174                 [Test]
175                 public void UploadFile1 ()
176                 {
177                         ServerPut sp = new ServerPut ();
178                         sp.Start ();
179                         string uri = String.Format ("ftp://{0}:{1}/uploads/file.txt", sp.IPAddress, sp.Port);
180                         try {
181                                 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
182                                 ftp.KeepAlive = false;
183                                 ftp.Timeout = 5000;
184                                 ftp.Method = WebRequestMethods.Ftp.UploadFile;
185                                 ftp.ContentLength = 1;
186                                 ftp.UseBinary = true;
187                                 Stream stream = ftp.GetRequestStream ();
188                                 stream.WriteByte (0);
189                                 stream.Close ();
190                                 FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ();
191                                 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "UP#01");
192                                 response.Close ();
193                         } catch (Exception) {
194                                 if (!String.IsNullOrEmpty (sp.Where))
195                                         throw new Exception (sp.Where);
196                                 throw;
197                         } finally {
198                                 sp.Stop ();
199                         }
200                 }
201
202                 [Test]
203                 public void DownloadFile1 ()
204                 {
205                         DownloadFile (new ServerDownload ());
206                 }
207
208                 void DownloadFile (ServerDownload sp)
209                 {
210                         sp.Start ();
211                         string uri = String.Format ("ftp://{0}:{1}/file.txt", sp.IPAddress, sp.Port);
212                         try {
213                                 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
214                                 ftp.KeepAlive = false;
215                                 ftp.Timeout = 5000;
216                                 ftp.Method = WebRequestMethods.Ftp.DownloadFile;
217                                 ftp.UseBinary = true;
218                                 FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ();
219                                 Assert.IsTrue ((int) response.StatusCode >= 100 && (int) response.StatusCode < 200, "DL#01");
220                                 using (Stream st = response.GetResponseStream ()) {
221                                 }
222                                 // This should be "220 Bye" or similar (no KeepAlive)
223                                 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DL#02");
224                                 response.Close ();
225                         } catch (Exception) {
226                                 if (!String.IsNullOrEmpty (sp.Where))
227                                         throw new Exception (sp.Where);
228                                 throw;
229                         } finally {
230                                 sp.Stop ();
231                         }
232                 }
233
234                 [Test]
235                 public void DownloadFile2 ()
236                 {
237                         // Some embedded FTP servers in Industrial Automation Hardware report
238                         // the PWD using backslashes, but allow forward slashes for CWD.
239                         DownloadFile (new ServerDownload (@"\Users\someuser", "/Users/someuser/"));
240                 }
241
242                 [Test]
243                 public void DeleteFile1 ()
244                 {
245                         ServerDeleteFile sp = new ServerDeleteFile ();
246                         sp.Start ();
247                         string uri = String.Format ("ftp://{0}:{1}/file.txt", sp.IPAddress, sp.Port);
248                         try {
249                                 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
250                                 Console.WriteLine (ftp.RequestUri);
251                                 ftp.KeepAlive = false;
252                                 ftp.Timeout = 5000;
253                                 ftp.Method = WebRequestMethods.Ftp.DeleteFile;
254                                 ftp.UseBinary = true;
255                                 FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ();
256                                 Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DF#01");
257                                 response.Close ();
258                         } catch (Exception e) {
259                                 Console.WriteLine (e);
260                                 if (!String.IsNullOrEmpty (sp.Where))
261                                         throw new Exception (sp.Where);
262                                 throw;
263                         } finally {
264                                 sp.Stop ();
265                         }
266                 }
267
268                 [Test]
269                 public void ListDirectory1 ()
270                 {
271                         ServerListDirectory sp = new ServerListDirectory ();
272                         sp.Start ();
273                         string uri = String.Format ("ftp://{0}:{1}/somedir/", sp.IPAddress, sp.Port);
274                         try {
275                                 FtpWebRequest ftp = (FtpWebRequest) WebRequest.Create (uri);
276                                 Console.WriteLine (ftp.RequestUri);
277                                 ftp.KeepAlive = false;
278                                 ftp.Timeout = 5000;
279                                 ftp.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
280                                 ftp.UseBinary = true;
281                                 using (FtpWebResponse response = (FtpWebResponse) ftp.GetResponse ()) {
282                                         StreamReader reader = new StreamReader (response.GetResponseStream ());
283                                         string result = reader.ReadToEnd ();
284                                         Assert.IsTrue ((int) response.StatusCode >= 200 && (int) response.StatusCode < 300, "DF#01");
285                                 }
286                         } catch (Exception e) {
287                                 Console.WriteLine (e);
288                                 if (!String.IsNullOrEmpty (sp.Where))
289                                         throw new Exception (sp.Where);
290                                 throw;
291                         } finally {
292                                 sp.Stop ();
293                         }
294                 }
295
296                 class ServerListDirectory : FtpServer {
297                         protected override void Run ()
298                         {
299                                 Socket client = control.Accept ();
300                                 NetworkStream ns = new NetworkStream (client, false);
301                                 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
302                                 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
303                                 if (!DoAnonymousLogin (writer, reader)) {
304                                         client.Close ();
305                                         return;
306                                 }
307
308                                 if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/somedir/")) {
309                                         client.Close ();
310                                         return;
311                                 }
312
313                                 string str = reader.ReadLine ();
314                                 if (str != "PASV") {
315                                         Where = "PASV";
316                                         client.Close ();
317                                         return;
318                                 }
319
320                                 IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint;
321                                 byte [] addr_bytes = end_data.Address.GetAddressBytes ();
322                                 byte [] port = new byte [2];
323                                 port[0] = (byte) ((end_data.Port >> 8) & 255);
324                                 port[1] = (byte) (end_data.Port & 255);
325                                 StringBuilder sb = new StringBuilder ("227 Passive (");
326                                 foreach (byte b in addr_bytes) {
327                                         sb.AppendFormat ("{0},", b);    
328                                 }
329                                 sb.AppendFormat ("{0},", port [0]);     
330                                 sb.AppendFormat ("{0})", port [1]);     
331                                 writer.WriteLine (sb.ToString ());
332                                 writer.Flush ();
333
334                                 str = reader.ReadLine ();
335                                 if (str != "LIST") {
336                                         Where = "LIST - '" + str + "'";
337                                         client.Close ();
338                                         return;
339                                 }
340                                 writer.WriteLine ("150 Here comes the directory listing");
341                                 writer.Flush ();
342
343                                 Socket data_cnc = data.Accept ();
344                                 byte [] dontcare = Encoding.ASCII.GetBytes ("drwxr-xr-x    2 ftp      ftp          4096 Oct 27 20:17 tests");
345                                 data_cnc.Send (dontcare, 1, SocketFlags.None);
346                                 data_cnc.Close ();
347                                 writer.WriteLine ("226 Directory send Ok");
348                                 writer.Flush ();
349                                 if (!EndConversation (writer, reader)) {
350                                         client.Close ();
351                                         return;
352                                 }
353                                 client.Close ();
354                         }
355                 }
356
357                 class ServerDeleteFile : FtpServer {
358                         protected override void Run ()
359                         {
360                                 Socket client = control.Accept ();
361                                 NetworkStream ns = new NetworkStream (client, false);
362                                 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
363                                 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
364                                 if (!DoAnonymousLogin (writer, reader)) {
365                                         client.Close ();
366                                         return;
367                                 }
368
369                                 if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/")) {
370                                         client.Close ();
371                                         return;
372                                 }
373
374                                 string str = reader.ReadLine ();
375                                 if (str.Trim () != "DELE file.txt") {
376                                         Where = "DELE - " + str;
377                                         client.Close ();
378                                         return;
379                                 }
380                                 writer.WriteLine ("250 Delete operation successful");
381                                 writer.Flush ();
382                                 if (!EndConversation (writer, reader)) {
383                                         client.Close ();
384                                         return;
385                                 }
386                                 client.Close ();
387                         }
388                 }
389
390                 class ServerDownload : FtpServer {
391
392                         string Pwd, Cwd;
393
394                         public ServerDownload ()
395                                 : this (null, null)
396                         {
397                         }
398
399                         public ServerDownload (string pwd, string cwd)
400                         {
401                                 Pwd = pwd ?? "/home/someuser";
402                                 Cwd = cwd ?? "/home/someuser/";
403                         }
404
405                         protected override void Run ()
406                         {
407                                 Socket client = control.Accept ();
408                                 NetworkStream ns = new NetworkStream (client, false);
409                                 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
410                                 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
411                                 if (!DoAnonymousLogin (writer, reader)) {
412                                         client.Close ();
413                                         return;
414                                 }
415
416                                 if (!DoInitialDialog (writer, reader, Pwd, Cwd)) {
417                                         client.Close ();
418                                         return;
419                                 }
420
421                                 string str = reader.ReadLine ();
422                                 if (str != "PASV") {
423                                         Where = "PASV";
424                                         client.Close ();
425                                         return;
426                                 }
427
428                                 IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint;
429                                 byte [] addr_bytes = end_data.Address.GetAddressBytes ();
430                                 byte [] port = new byte [2];
431                                 port[0] = (byte) ((end_data.Port >> 8) & 255);
432                                 port[1] = (byte) (end_data.Port & 255);
433                                 StringBuilder sb = new StringBuilder ("227 Passive (");
434                                 foreach (byte b in addr_bytes) {
435                                         sb.AppendFormat ("{0},", b);    
436                                 }
437                                 sb.AppendFormat ("{0},", port [0]);     
438                                 sb.AppendFormat ("{0})", port [1]);     
439                                 writer.WriteLine (sb.ToString ());
440                                 writer.Flush ();
441
442                                 str = reader.ReadLine ();
443                                 if (str != "RETR file.txt") {
444                                         Where = "RETR - " + str;
445                                         client.Close ();
446                                         return;
447                                 }
448                                 writer.WriteLine ("150 Opening BINARY mode data connection for blah (n bytes)");
449                                 writer.Flush ();
450
451                                 Socket data_cnc = data.Accept ();
452                                 byte [] dontcare = new byte [1];
453                                 data_cnc.Receive (dontcare, 1, SocketFlags.None);
454                                 data_cnc.Close ();
455                                 writer.WriteLine ("226 File send Ok");
456                                 writer.Flush ();
457                                 if (!EndConversation (writer, reader)) {
458                                         client.Close ();
459                                         return;
460                                 }
461                                 client.Close ();
462                         }
463                 }
464
465                 class ServerPut : FtpServer {
466                         protected override void Run ()
467                         {
468                                 Socket client = control.Accept ();
469                                 NetworkStream ns = new NetworkStream (client, false);
470                                 StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
471                                 StreamReader reader = new StreamReader (ns, Encoding.UTF8);
472                                 if (!DoAnonymousLogin (writer, reader)) {
473                                         client.Close ();
474                                         return;
475                                 }
476
477                                 if (!DoInitialDialog (writer, reader, "/home/someuser", "/home/someuser/uploads/")) {
478                                         client.Close ();
479                                         return;
480                                 }
481
482                                 string str = reader.ReadLine ();
483                                 if (str != "PASV") {
484                                         Where = "PASV";
485                                         client.Close ();
486                                         return;
487                                 }
488
489                                 IPEndPoint end_data = (IPEndPoint) data.LocalEndPoint;
490                                 byte [] addr_bytes = end_data.Address.GetAddressBytes ();
491                                 byte [] port = new byte [2];
492                                 port[0] = (byte) ((end_data.Port >> 8) & 255);
493                                 port[1] = (byte) (end_data.Port & 255);
494                                 StringBuilder sb = new StringBuilder ("227 Passive (");
495                                 foreach (byte b in addr_bytes) {
496                                         sb.AppendFormat ("{0},", b);    
497                                 }
498                                 sb.AppendFormat ("{0},", port [0]);     
499                                 sb.AppendFormat ("{0})", port [1]);     
500                                 writer.WriteLine (sb.ToString ());
501                                 writer.Flush ();
502
503                                 str = reader.ReadLine ();
504                                 if (str != "STOR file.txt") {
505                                         Where = "STOR - " + str;
506                                         client.Close ();
507                                         return;
508                                 }
509                                 writer.WriteLine ("150 Ok to send data");
510                                 writer.Flush ();
511
512                                 Socket data_cnc = data.Accept ();
513                                 byte [] dontcare = new byte [1];
514                                 data_cnc.Receive (dontcare, 1, SocketFlags.None);
515                                 data_cnc.Close ();
516                                 writer.WriteLine ("226 File received Ok");
517                                 writer.Flush ();
518                                 if (!EndConversation (writer, reader)) {
519                                         client.Close ();
520                                         return;
521                                 }
522                                 client.Close ();
523                         }
524                 }
525
526                 abstract class FtpServer {
527                         protected Socket control;
528                         protected Socket data;
529                         protected ManualResetEvent evt;
530                         public string Where = "";
531
532                         public FtpServer ()
533                         {
534                                 control = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
535                                 control.Bind (new IPEndPoint (IPAddress.Loopback, 0));
536                                 control.Listen (1);
537                                 data = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
538                                 data.Bind (new IPEndPoint (IPAddress.Loopback, 0));
539                                 data.Listen (1);
540                         }
541
542                         public void Start ()
543                         {
544                                 evt = new ManualResetEvent (false);
545                                 Thread th = new Thread (new ThreadStart (Run));
546                                 th.Start ();
547                         }
548
549                         public void Stop ()
550                         {
551                                 evt.Set ();
552                                 data.Close ();
553                                 control.Close ();
554                         }
555
556                         // PWD, CWD and TYPE I (type could be moved out of here)
557                         protected bool DoInitialDialog (StreamWriter writer, StreamReader reader, string pwd, string cwd)
558                         {
559                                 string str = reader.ReadLine ();
560                                 if (!str.StartsWith ("OPTS utf8 on")) {
561                                         Where = "OPTS utf8 - " + str;
562                                         return false;
563                                 }
564                                 writer.WriteLine ("200 Always in UTF8 mode"); // vsftpd
565                                 writer.Flush ();
566                                 str = reader.ReadLine ();
567                                 if (!str.StartsWith ("PWD")) {
568                                         Where = "PWD - " + str;
569                                         return false;
570                                 }
571                                 writer.WriteLine ("257 \"{0}\"", pwd);
572                                 writer.Flush ();
573                                 str = reader.ReadLine ();
574                                 if (str != ("CWD " + cwd)) {
575                                         Where = "CWD - " + str;
576                                         return false;
577                                 }
578                                 writer.WriteLine ("250 Directory changed");
579                                 writer.Flush ();
580                                 str = reader.ReadLine ();
581                                 if (str != ("TYPE I")) {
582                                         Where = "TYPE - " + str;
583                                         return false;
584                                 }
585                                 writer.WriteLine ("200 Switching to binary mode");
586                                 writer.Flush ();
587                                 return true;
588                         }
589
590                         protected bool EndConversation (StreamWriter writer, StreamReader reader)
591                         {
592                                 string str = reader.ReadLine ();
593                                 if (str != "QUIT") {
594                                         Where = "QUIT";
595                                         return false;
596                                 }
597                                 writer.WriteLine ("220 Bye");
598                                 writer.Flush ();
599                                 Thread.Sleep (250);
600                                 return true;
601                         }
602
603                         protected bool DoAnonymousLogin (StreamWriter writer, StreamReader reader)
604                         {
605                                 writer.WriteLine ("220 Welcome to the jungle");
606                                 writer.Flush ();
607                                 string str = reader.ReadLine ();
608                                 if (!str.StartsWith ("USER ")) {
609                                         Where = "USER";
610                                         return false;
611                                 }
612                                 writer.WriteLine ("331 Say 'Mellon'");
613                                 writer.Flush ();
614                                 str = reader.ReadLine ();
615                                 if (!str.StartsWith ("PASS ")) {
616                                         Where = "PASS";
617                                         return false;
618                                 }
619                                 writer.WriteLine ("230 Logged in");
620                                 writer.Flush ();
621                                 return true;
622                         }
623                         
624                         public IPAddress IPAddress {
625                                 get { return ((IPEndPoint) control.LocalEndPoint).Address; }
626                         }
627                         
628                         public int Port {
629                                 get { return ((IPEndPoint) control.LocalEndPoint).Port; }
630                         }
631
632                         protected abstract void Run ();
633                 }
634         }
635 }
636
637