3 // - Unit tests for System.Net.HttpListener
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
31 using System.Net.Sockets;
32 using System.Threading;
33 using NUnit.Framework;
35 namespace MonoTests.System.Net {
37 public class HttpListenerTest {
42 public void SetUp () {
43 port = new Random ().Next (7777, 8000);
47 public void DefaultProperties ()
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");
62 HttpListener listener = new HttpListener ();
69 HttpListener listener = new HttpListener ();
74 [ExpectedException (typeof (InvalidOperationException))]
75 public void GetContext1 ()
77 HttpListener listener = new HttpListener ();
78 // "Please call Start () before calling this method"
79 listener.GetContext ();
83 [ExpectedException (typeof (InvalidOperationException))]
84 public void GetContext2 ()
86 HttpListener listener = new HttpListener ();
88 // "Please call AddPrefix () before calling this method"
89 listener.GetContext ();
93 [ExpectedException (typeof (InvalidOperationException))]
94 public void BeginGetContext1 ()
96 HttpListener listener = new HttpListener ();
97 // "Please call Start () before calling this method"
98 listener.BeginGetContext (null, null);
102 public void BeginGetContext2 ()
104 HttpListener listener = new HttpListener ();
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);
113 private bool CanOpenPort(int port)
117 using(Socket socket = new Socket (AddressFamily.InterNetwork,
121 socket.Bind (new IPEndPoint (IPAddress.Loopback, port));
126 //Can be AccessDeniedException(ports 80/443 need root access) or
127 //SocketException because other application is listening
134 public void DefaultHttpPort ()
136 if (!CanOpenPort (80))
137 Assert.Ignore ("Can not open port 80 skipping test.");
138 using(HttpListener listener = new HttpListener ())
140 listener.Prefixes.Add ("http://127.0.0.1/");
142 Assert.IsFalse (CanOpenPort (80), "HttpListener is not listening on port 80.");
147 public void DefaultHttpsPort ()
149 if (!CanOpenPort (443))
150 Assert.Ignore ("Can not open port 443 skipping test.");
151 using(HttpListener listener = new HttpListener ())
153 listener.Prefixes.Add ("https://127.0.0.1/");
155 Assert.IsFalse (CanOpenPort (443), "HttpListener is not listening on port 443.");
160 public void TwoListeners_SameAddress ()
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/");
173 [ExpectedException (typeof (HttpListenerException))]
174 public void TwoListeners_SameURL ()
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/");
187 [ExpectedException (typeof (HttpListenerException))]
188 public void MultipleSlashes ()
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.
199 [ExpectedException (typeof (HttpListenerException))]
200 public void PercentSign ()
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.
211 public void CloseBeforeStart ()
213 HttpListener listener = new HttpListener ();
218 public void CloseTwice ()
220 if (!CanOpenPort (port))
221 Assert.Ignore ("port");
222 HttpListener listener = new HttpListener ();
223 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
230 public void StartStopStart ()
232 if (!CanOpenPort (port))
233 Assert.Ignore ("port");
234 HttpListener listener = new HttpListener ();
235 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
243 public void StartStopDispose ()
245 if (!CanOpenPort (port))
246 Assert.Ignore ("port");
247 using (HttpListener listener = new HttpListener ()){
248 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
255 public void AbortBeforeStart ()
257 HttpListener listener = new HttpListener ();
262 public void AbortTwice ()
264 if (!CanOpenPort (port))
265 Assert.Ignore ("port");
266 HttpListener listener = new HttpListener ();
267 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
274 public void PropertiesWhenClosed1 ()
276 HttpListener listener = new HttpListener ();
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");
287 [ExpectedException (typeof (ObjectDisposedException))]
288 public void PropertiesWhenClosed2 ()
290 HttpListener listener = new HttpListener ();
292 HttpListenerPrefixCollection p = listener.Prefixes;
296 [ExpectedException (typeof (ObjectDisposedException))]
297 public void PropertiesWhenClosedSet1 ()
299 HttpListener listener = new HttpListener ();
301 listener.AuthenticationSchemes = AuthenticationSchemes.None;
305 [ExpectedException (typeof (ObjectDisposedException))]
306 public void PropertiesWhenClosedSet2 ()
308 HttpListener listener = new HttpListener ();
310 listener.AuthenticationSchemeSelectorDelegate = null;
314 [ExpectedException (typeof (ObjectDisposedException))]
315 public void PropertiesWhenClosedSet3 ()
317 HttpListener listener = new HttpListener ();
319 listener.IgnoreWriteExceptions = true;
323 [ExpectedException (typeof (ObjectDisposedException))]
324 public void PropertiesWhenClosedSet4 ()
326 HttpListener listener = new HttpListener ();
328 listener.Realm = "hola";
332 [ExpectedException (typeof (ObjectDisposedException))]
333 public void PropertiesWhenClosedSet5 ()
335 HttpListener listener = new HttpListener ();
337 listener.UnsafeConnectionNtlmAuthentication = true;
341 public void PropertiesWhenClosed3 ()
343 HttpListener listener = new HttpListener ();
345 Assert.IsFalse (listener.IsListening);
349 public void CloseWhileBegin ()
351 HttpListener listener = new HttpListener ();
352 listener.Prefixes.Add ("http://127.0.0.1:9001/closewhilebegin/");
354 CallMe cm = new CallMe ();
355 listener.BeginGetContext (cm.Callback, listener);
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");
365 public void AbortWhileBegin ()
367 HttpListener listener = new HttpListener ();
368 listener.Prefixes.Add ("http://127.0.0.1:9001/abortwhilebegin/");
370 CallMe cm = new CallMe ();
371 listener.BeginGetContext (cm.Callback, listener);
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");
381 [ExpectedException (typeof (HttpListenerException))]
382 public void CloseWhileGet ()
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()
389 HttpListener listener = new HttpListener ();
390 listener.Prefixes.Add ("http://127.0.0.1:9001/closewhileget/");
392 RunMe rm = new RunMe (1000, new ThreadStart (listener.Close), new object [0]);
394 HttpListenerContext ctx = listener.GetContext ();
398 [ExpectedException (typeof (HttpListenerException))]
399 public void AbortWhileGet ()
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()
406 HttpListener listener = new HttpListener ();
407 listener.Prefixes.Add ("http://127.0.0.1:9001/abortwhileget/");
409 RunMe rm = new RunMe (1000, new ThreadStart (listener.Abort), new object [0]);
411 HttpListenerContext ctx = listener.GetContext ();
418 public object Result;
420 public RunMe (int delay_ms, Delegate d, object [] args)
422 this.delay_ms = delay_ms;
429 Thread th = new Thread (new ThreadStart (Run));
435 Thread.Sleep (delay_ms);
436 Result = d.DynamicInvoke (args);
441 public ManualResetEvent Event = new ManualResetEvent (false);
443 public HttpListenerContext Context;
444 public Exception Error;
454 public void Callback (IAsyncResult ares)
458 Error = new ArgumentNullException ("ares");
463 HttpListener listener = (HttpListener) ares.AsyncState;
464 Context = listener.EndGetContext (ares);
465 } catch (Exception e) {
471 public void Dispose ()
478 public void ConnectionReuse ()
480 var uri = "http://localhost:1338/";
482 HttpListener listener = new HttpListener ();
483 listener.Prefixes.Add (uri);
486 IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri);
488 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1");
489 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2");
492 public IPEndPoint CreateListenerRequest (HttpListener listener, string uri)
494 IPEndPoint ipEndPoint = null;
495 listener.BeginGetContext ((result) => ipEndPoint = ListenerCallback (result), listener);
497 var request = (HttpWebRequest) WebRequest.Create (uri);
498 request.Method = "POST";
500 // We need to write something
501 request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1);
502 request.GetRequestStream ().Dispose ();
504 // Send request, socket is created or reused.
505 var response = request.GetResponse ();
507 // Close response so socket can be reused.
513 public static IPEndPoint ListenerCallback (IAsyncResult result)
515 var listener = (HttpListener) result.AsyncState;
516 var context = listener.EndGetContext (result);
517 var clientEndPoint = context.Request.RemoteEndPoint;
519 // Disposing InputStream should not avoid socket reuse
520 context.Request.InputStream.Dispose ();
522 // Close OutputStream to send response
523 context.Response.OutputStream.Close ();
525 return clientEndPoint;