FtpWebRequestTest.cs 16 KB

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