Show thumbnail images in SWF.(Open,Save)FileDialog
[mono.git] / mcs / class / System / Test / System.Net / HttpListenerTest.cs
1 //
2 // HttpListenerTest.cs
3 //      - Unit tests for System.Net.HttpListener
4 //
5 // Author:
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Net;
31 using System.Net.Sockets;
32 using System.Threading;
33 using NUnit.Framework;
34
35 namespace MonoTests.System.Net {
36         [TestFixture]
37         public class HttpListenerTest {
38
39                 int port;
40
41                 [SetUp]
42                 public void SetUp () {
43                         port = new Random ().Next (7777, 8000);
44                 }
45
46                 [Test]
47                 public void DefaultProperties ()
48                 {
49                         HttpListener listener = new HttpListener ();
50                         Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
51                         Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
52                         Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
53                         Assert.AreEqual (false, listener.IsListening, "#03");
54                         Assert.AreEqual (0, listener.Prefixes.Count, "#04");
55                         Assert.AreEqual (null, listener.Realm, "#05");
56                         Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
57                 }
58
59                 [Test]
60                 public void Start1 ()
61                 {
62                         HttpListener listener = new HttpListener ();
63                         listener.Start ();
64                 }
65
66                 [Test]
67                 public void Stop1 ()
68                 {
69                         HttpListener listener = new HttpListener ();
70                         listener.Stop ();
71                 }
72
73                 [Test]
74                 [ExpectedException (typeof (InvalidOperationException))]
75                 public void GetContext1 ()
76                 {
77                         HttpListener listener = new HttpListener ();
78                         // "Please call Start () before calling this method"
79                         listener.GetContext ();
80                 }
81
82                 [Test]
83                 [ExpectedException (typeof (InvalidOperationException))]
84                 public void GetContext2 ()
85                 {
86                         HttpListener listener = new HttpListener ();
87                         listener.Start ();
88                         // "Please call AddPrefix () before calling this method"
89                         listener.GetContext ();
90                 }
91
92                 [Test]
93                 [ExpectedException (typeof (InvalidOperationException))]
94                 public void BeginGetContext1 ()
95                 {
96                         HttpListener listener = new HttpListener ();
97                         // "Please call Start () before calling this method"
98                         listener.BeginGetContext (null, null);
99                 }
100
101                 [Test]
102                 public void BeginGetContext2 ()
103                 {
104                         HttpListener listener = new HttpListener ();
105                         listener.Start ();
106                         // One would expect this to fail as BeginGetContext1 does not fail and
107                         // calling EndGetContext will wait forever.
108                         // Lame. They should check that we have no prefixes.
109                         IAsyncResult ares = listener.BeginGetContext (null, null);
110                         Assert.IsFalse (ares.IsCompleted);
111                 }
112
113                 private bool CanOpenPort(int port)
114                 {
115                         try
116                         {
117                                 using(Socket socket = new Socket (AddressFamily.InterNetwork,
118                                         SocketType.Stream,
119                                         ProtocolType.Tcp))
120                                 {
121                                         socket.Bind (new IPEndPoint (IPAddress.Loopback, port));
122                                         socket.Listen(1);
123                                 }
124                         }
125                         catch(Exception) {
126                                 //Can be AccessDeniedException(ports 80/443 need root access) or
127                                 //SocketException because other application is listening
128                                 return false;
129                         }
130                         return true;
131                 }
132
133                 [Test]
134                 public void DefaultHttpPort ()
135                 {
136                         if (!CanOpenPort (80))
137                                 Assert.Ignore ("Can not open port 80 skipping test.");
138                         using(HttpListener listener = new HttpListener ())
139                         {
140                                 listener.Prefixes.Add ("http://127.0.0.1/");
141                                 listener.Start ();
142                                 Assert.IsFalse (CanOpenPort (80), "HttpListener is not listening on port 80.");
143                         }
144                 }
145
146                 [Test]
147                 public void DefaultHttpsPort ()
148                 {
149                         if (!CanOpenPort (443))
150                                 Assert.Ignore ("Can not open port 443 skipping test.");
151                         using(HttpListener listener = new HttpListener ())
152                         {
153                                 listener.Prefixes.Add ("https://127.0.0.1/");
154                                 listener.Start ();
155                                 Assert.IsFalse (CanOpenPort (443), "HttpListener is not listening on port 443.");
156                         }
157                 }
158
159                 [Test]
160                 public void TwoListeners_SameAddress ()
161                 {
162                         if (!CanOpenPort (port))
163                                 Assert.Ignore ("port");
164                         HttpListener listener1 = new HttpListener ();
165                         listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/");
166                         HttpListener listener2 = new HttpListener ();
167                         listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
168                         listener1.Start ();
169                         listener2.Start ();
170                 }
171
172                 [Test]
173                 [ExpectedException (typeof (HttpListenerException))]
174                 public void TwoListeners_SameURL ()
175                 {
176                         if (!CanOpenPort (port))
177                                 Assert.Ignore ("port");
178                         HttpListener listener1 = new HttpListener ();
179                         listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
180                         HttpListener listener2 = new HttpListener ();
181                         listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
182                         listener1.Start ();
183                         listener2.Start ();
184                 }
185
186                 [Test]
187                 [ExpectedException (typeof (HttpListenerException))]
188                 public void MultipleSlashes ()
189                 {
190                         if (!CanOpenPort (port))
191                                 Assert.Ignore ("port");
192                         HttpListener listener = new HttpListener ();
193                         listener.Prefixes.Add ("http://localhost:" + port + "/hola////");
194                         // this one throws on Start(), not when adding it.
195                         listener.Start ();
196                 }
197
198                 [Test]
199                 [ExpectedException (typeof (HttpListenerException))]
200                 public void PercentSign ()
201                 {
202                         if (!CanOpenPort (port))
203                                 Assert.Ignore ("port");
204                         HttpListener listener = new HttpListener ();
205                         listener.Prefixes.Add ("http://localhost:" + port + "/hola%3E/");
206                         // this one throws on Start(), not when adding it.
207                         listener.Start ();
208                 }
209
210                 [Test]
211                 public void CloseBeforeStart ()
212                 {
213                         HttpListener listener = new HttpListener ();
214                         listener.Close ();
215                 }
216
217                 [Test]
218                 public void CloseTwice ()
219                 {
220                         if (!CanOpenPort (port))
221                                 Assert.Ignore ("port");
222                         HttpListener listener = new HttpListener ();
223                         listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
224                         listener.Start ();
225                         listener.Close ();
226                         listener.Close ();
227                 }
228
229                 [Test]
230                 public void StartStopStart ()
231                 {
232                         if (!CanOpenPort (port))
233                                 Assert.Ignore ("port");
234                         HttpListener listener = new HttpListener ();
235                         listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
236                         listener.Start ();
237                         listener.Stop ();
238                         listener.Start ();
239                         listener.Close ();
240                 }
241
242                 [Test]
243                 public void StartStopDispose ()
244                 {
245                         if (!CanOpenPort (port))
246                                 Assert.Ignore ("port");
247                         using (HttpListener listener = new HttpListener ()){
248                                 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
249                                 listener.Start ();
250                                 listener.Stop ();
251                         }
252                 }
253                 
254                 [Test]
255                 public void AbortBeforeStart ()
256                 {
257                         HttpListener listener = new HttpListener ();
258                         listener.Abort ();
259                 }
260
261                 [Test]
262                 public void AbortTwice ()
263                 {
264                         if (!CanOpenPort (port))
265                                 Assert.Ignore ("port");
266                         HttpListener listener = new HttpListener ();
267                         listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
268                         listener.Start ();
269                         listener.Abort ();
270                         listener.Abort ();
271                 }
272
273                 [Test]
274                 public void PropertiesWhenClosed1 ()
275                 {
276                         HttpListener listener = new HttpListener ();
277                         listener.Close ();
278                         Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
279                         Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
280                         Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
281                         Assert.AreEqual (false, listener.IsListening, "#03");
282                         Assert.AreEqual (null, listener.Realm, "#05");
283                         Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
284                 }
285
286                 [Test]
287                 [ExpectedException (typeof (ObjectDisposedException))]
288                 public void PropertiesWhenClosed2 ()
289                 {
290                         HttpListener listener = new HttpListener ();
291                         listener.Close ();
292                         HttpListenerPrefixCollection p = listener.Prefixes;
293                 }
294
295                 [Test]
296                 [ExpectedException (typeof (ObjectDisposedException))]
297                 public void PropertiesWhenClosedSet1 ()
298                 {
299                         HttpListener listener = new HttpListener ();
300                         listener.Close ();
301                         listener.AuthenticationSchemes = AuthenticationSchemes.None;
302                 }
303
304                 [Test]
305                 [ExpectedException (typeof (ObjectDisposedException))]
306                 public void PropertiesWhenClosedSet2 ()
307                 {
308                         HttpListener listener = new HttpListener ();
309                         listener.Close ();
310                         listener.AuthenticationSchemeSelectorDelegate = null;
311                 }
312
313                 [Test]
314                 [ExpectedException (typeof (ObjectDisposedException))]
315                 public void PropertiesWhenClosedSet3 ()
316                 {
317                         HttpListener listener = new HttpListener ();
318                         listener.Close ();
319                         listener.IgnoreWriteExceptions = true;
320                 }
321
322                 [Test]
323                 [ExpectedException (typeof (ObjectDisposedException))]
324                 public void PropertiesWhenClosedSet4 ()
325                 {
326                         HttpListener listener = new HttpListener ();
327                         listener.Close ();
328                         listener.Realm = "hola";
329                 }
330
331                 [Test]
332                 [ExpectedException (typeof (ObjectDisposedException))]
333                 public void PropertiesWhenClosedSet5 ()
334                 {
335                         HttpListener listener = new HttpListener ();
336                         listener.Close ();
337                         listener.UnsafeConnectionNtlmAuthentication = true;
338                 }
339
340                 [Test]
341                 public void PropertiesWhenClosed3 ()
342                 {
343                         HttpListener listener = new HttpListener ();
344                         listener.Close ();
345                         Assert.IsFalse (listener.IsListening);
346                 }
347
348                 [Test]
349                 public void CloseWhileBegin ()
350                 {
351                         HttpListener listener = new HttpListener ();
352                         listener.Prefixes.Add ("http://127.0.0.1:9001/closewhilebegin/");
353                         listener.Start ();
354                         CallMe cm = new CallMe ();
355                         listener.BeginGetContext (cm.Callback, listener);
356                         listener.Close ();
357                         if (false == cm.Event.WaitOne (3000, false))
358                                 Assert.Fail ("This should not time out.");
359                         Assert.IsNotNull (cm.Error);
360                         Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
361                         cm.Dispose ();
362                 }
363
364                 [Test]
365                 public void AbortWhileBegin ()
366                 {
367                         HttpListener listener = new HttpListener ();
368                         listener.Prefixes.Add ("http://127.0.0.1:9001/abortwhilebegin/");
369                         listener.Start ();
370                         CallMe cm = new CallMe ();
371                         listener.BeginGetContext (cm.Callback, listener);
372                         listener.Abort ();
373                         if (false == cm.Event.WaitOne (3000, false))
374                                 Assert.Fail ("This should not time out.");
375                         Assert.IsNotNull (cm.Error);
376                         Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
377                         cm.Dispose ();
378                 }
379
380                 [Test]
381                 [ExpectedException (typeof (HttpListenerException))]
382                 public void CloseWhileGet ()
383                 {
384                         // "System.Net.HttpListener Exception : The I/O operation has been aborted
385                         // because of either a thread exit or an application request
386                         //   at System.Net.HttpListener.GetContext()
387                         //   at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
388
389                         HttpListener listener = new HttpListener ();
390                         listener.Prefixes.Add ("http://127.0.0.1:9001/closewhileget/");
391                         listener.Start ();
392                         RunMe rm = new RunMe (1000, new ThreadStart (listener.Close), new object [0]);
393                         rm.Start ();
394                         HttpListenerContext ctx = listener.GetContext ();
395                 }
396
397                 [Test]
398                 [ExpectedException (typeof (HttpListenerException))]
399                 public void AbortWhileGet ()
400                 {
401                         // "System.Net.HttpListener Exception : The I/O operation has been aborted
402                         // because of either a thread exit or an application request
403                         //   at System.Net.HttpListener.GetContext()
404                         //   at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
405
406                         HttpListener listener = new HttpListener ();
407                         listener.Prefixes.Add ("http://127.0.0.1:9001/abortwhileget/");
408                         listener.Start ();
409                         RunMe rm = new RunMe (1000, new ThreadStart (listener.Abort), new object [0]);
410                         rm.Start ();
411                         HttpListenerContext ctx = listener.GetContext ();
412                 }
413
414                 class RunMe {
415                         Delegate d;
416                         int delay_ms;
417                         object [] args;
418                         public object Result;
419
420                         public RunMe (int delay_ms, Delegate d, object [] args)
421                         {
422                                 this.delay_ms = delay_ms;
423                                 this.d = d;
424                                 this.args = args;
425                         }
426
427                         public void Start ()
428                         {
429                                 Thread th = new Thread (new ThreadStart (Run));
430                                 th.Start ();
431                         }
432
433                         void Run ()
434                         {
435                                 Thread.Sleep (delay_ms);
436                                 Result = d.DynamicInvoke (args);
437                         }
438                 }
439
440                 class CallMe {
441                         public ManualResetEvent Event = new ManualResetEvent (false);
442                         public bool Called;
443                         public HttpListenerContext Context;
444                         public Exception Error;
445
446                         public void Reset ()
447                         {
448                                 Called = false;
449                                 Context = null;
450                                 Error = null;
451                                 Event.Reset ();
452                         }
453
454                         public void Callback (IAsyncResult ares)
455                         {
456                                 Called = true;
457                                 if (ares == null) {
458                                         Error = new ArgumentNullException ("ares");
459                                         return;
460                                 }
461                                 
462                                 try {
463                                         HttpListener listener = (HttpListener) ares.AsyncState;
464                                         Context = listener.EndGetContext (ares);
465                                 } catch (Exception e) {
466                                         Error = e;
467                                 }
468                                 Event.Set ();
469                         }
470
471                         public void Dispose ()
472                         {
473                                 Event.Close ();
474                         }
475                 }
476
477                 [Test]
478                 public void ConnectionReuse ()
479                 {
480                         var uri = "http://localhost:1338/";
481
482                         HttpListener listener = new HttpListener ();
483                         listener.Prefixes.Add (uri);
484                         listener.Start ();
485
486                         IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri);
487
488                         Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1");
489                         Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2");
490                 }
491
492                 public IPEndPoint CreateListenerRequest (HttpListener listener, string uri)
493                 {
494                         IPEndPoint ipEndPoint = null;
495                         listener.BeginGetContext ((result) => ipEndPoint = ListenerCallback (result), listener);
496
497                         var request = (HttpWebRequest) WebRequest.Create (uri);
498                         request.Method = "POST";
499
500                         // We need to write something
501                         request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1);
502                         request.GetRequestStream ().Dispose ();
503
504                         // Send request, socket is created or reused.
505                         var response = request.GetResponse ();
506
507                         // Close response so socket can be reused.
508                         response.Close ();
509
510                         return ipEndPoint;
511                 }
512
513                 public static IPEndPoint ListenerCallback (IAsyncResult result)
514                 {
515                         var listener = (HttpListener) result.AsyncState;
516                         var context = listener.EndGetContext (result);
517                         var clientEndPoint = context.Request.RemoteEndPoint;
518
519                         // Disposing InputStream should not avoid socket reuse
520                         context.Request.InputStream.Dispose ();
521
522                         // Close OutputStream to send response
523                         context.Response.OutputStream.Close ();
524
525                         return clientEndPoint;
526                 }
527         }
528 }
529