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;
34 using MonoTests.Helpers;
36 namespace MonoTests.System.Net {
38 public class HttpListenerTest {
43 public void SetUp () {
44 port = NetworkHelpers.FindFreePort ();
48 public void DefaultProperties ()
50 HttpListener listener = new HttpListener ();
51 Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
52 Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
53 Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
54 Assert.AreEqual (false, listener.IsListening, "#03");
55 Assert.AreEqual (0, listener.Prefixes.Count, "#04");
56 Assert.AreEqual (null, listener.Realm, "#05");
57 Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
63 HttpListener listener = new HttpListener ();
70 HttpListener listener = new HttpListener ();
75 [ExpectedException (typeof (InvalidOperationException))]
76 public void GetContext1 ()
78 HttpListener listener = new HttpListener ();
79 // "Please call Start () before calling this method"
80 listener.GetContext ();
84 [ExpectedException (typeof (InvalidOperationException))]
85 public void GetContext2 ()
87 HttpListener listener = new HttpListener ();
89 // "Please call AddPrefix () before calling this method"
90 listener.GetContext ();
94 [ExpectedException (typeof (InvalidOperationException))]
95 public void BeginGetContext1 ()
97 HttpListener listener = new HttpListener ();
98 // "Please call Start () before calling this method"
99 listener.BeginGetContext (null, null);
103 public void BeginGetContext2 ()
105 HttpListener listener = new HttpListener ();
107 // One would expect this to fail as BeginGetContext1 does not fail and
108 // calling EndGetContext will wait forever.
109 // Lame. They should check that we have no prefixes.
110 IAsyncResult ares = listener.BeginGetContext (null, null);
111 Assert.IsFalse (ares.IsCompleted);
114 private bool CanOpenPort(int port)
118 using(Socket socket = new Socket (AddressFamily.InterNetwork,
122 socket.Bind (new IPEndPoint (IPAddress.Loopback, port));
127 //Can be AccessDeniedException(ports 80/443 need root access) or
128 //SocketException because other application is listening
135 public void DefaultHttpPort ()
137 if (!CanOpenPort (80))
138 Assert.Ignore ("Can not open port 80 skipping test.");
139 using(HttpListener listener = new HttpListener ())
141 listener.Prefixes.Add ("http://127.0.0.1/");
143 Assert.IsFalse (CanOpenPort (80), "HttpListener is not listening on port 80.");
148 public void DefaultHttpsPort ()
150 if (!CanOpenPort (443))
151 Assert.Ignore ("Can not open port 443 skipping test.");
152 using(HttpListener listener = new HttpListener ())
154 listener.Prefixes.Add ("https://127.0.0.1/");
156 Assert.IsFalse (CanOpenPort (443), "HttpListener is not listening on port 443.");
161 public void TwoListeners_SameAddress ()
163 if (!CanOpenPort (port))
164 Assert.Ignore ("port");
165 HttpListener listener1 = new HttpListener ();
166 listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/");
167 HttpListener listener2 = new HttpListener ();
168 listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
174 [ExpectedException (typeof (HttpListenerException))]
175 public void TwoListeners_SameURL ()
177 if (!CanOpenPort (port))
178 Assert.Ignore ("port");
179 HttpListener listener1 = new HttpListener ();
180 listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
181 HttpListener listener2 = new HttpListener ();
182 listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
188 [ExpectedException (typeof (HttpListenerException))]
189 public void MultipleSlashes ()
191 if (!CanOpenPort (port))
192 Assert.Ignore ("port");
193 HttpListener listener = new HttpListener ();
194 listener.Prefixes.Add ("http://localhost:" + port + "/hola////");
195 // this one throws on Start(), not when adding it.
200 [ExpectedException (typeof (HttpListenerException))]
201 public void PercentSign ()
203 if (!CanOpenPort (port))
204 Assert.Ignore ("port");
205 HttpListener listener = new HttpListener ();
206 listener.Prefixes.Add ("http://localhost:" + port + "/hola%3E/");
207 // this one throws on Start(), not when adding it.
212 public void CloseBeforeStart ()
214 HttpListener listener = new HttpListener ();
219 public void CloseTwice ()
221 if (!CanOpenPort (port))
222 Assert.Ignore ("port");
223 HttpListener listener = new HttpListener ();
224 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
231 public void StartStopStart ()
233 if (!CanOpenPort (port))
234 Assert.Ignore ("port");
235 HttpListener listener = new HttpListener ();
236 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
244 public void StartStopDispose ()
246 if (!CanOpenPort (port))
247 Assert.Ignore ("port");
248 using (HttpListener listener = new HttpListener ()){
249 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
256 public void AbortBeforeStart ()
258 HttpListener listener = new HttpListener ();
263 public void AbortTwice ()
265 if (!CanOpenPort (port))
266 Assert.Ignore ("port");
267 HttpListener listener = new HttpListener ();
268 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
275 public void PropertiesWhenClosed1 ()
277 HttpListener listener = new HttpListener ();
279 Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
280 Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
281 Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
282 Assert.AreEqual (false, listener.IsListening, "#03");
283 Assert.AreEqual (null, listener.Realm, "#05");
284 Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
288 [ExpectedException (typeof (ObjectDisposedException))]
289 public void PropertiesWhenClosed2 ()
291 HttpListener listener = new HttpListener ();
293 HttpListenerPrefixCollection p = listener.Prefixes;
297 [ExpectedException (typeof (ObjectDisposedException))]
298 public void PropertiesWhenClosedSet1 ()
300 HttpListener listener = new HttpListener ();
302 listener.AuthenticationSchemes = AuthenticationSchemes.None;
306 [ExpectedException (typeof (ObjectDisposedException))]
307 public void PropertiesWhenClosedSet2 ()
309 HttpListener listener = new HttpListener ();
311 listener.AuthenticationSchemeSelectorDelegate = null;
315 [ExpectedException (typeof (ObjectDisposedException))]
316 public void PropertiesWhenClosedSet3 ()
318 HttpListener listener = new HttpListener ();
320 listener.IgnoreWriteExceptions = true;
324 [ExpectedException (typeof (ObjectDisposedException))]
325 public void PropertiesWhenClosedSet4 ()
327 HttpListener listener = new HttpListener ();
329 listener.Realm = "hola";
333 [ExpectedException (typeof (ObjectDisposedException))]
334 public void PropertiesWhenClosedSet5 ()
336 HttpListener listener = new HttpListener ();
338 listener.UnsafeConnectionNtlmAuthentication = true;
342 public void PropertiesWhenClosed3 ()
344 HttpListener listener = new HttpListener ();
346 Assert.IsFalse (listener.IsListening);
350 public void CloseWhileBegin ()
352 HttpListener listener = new HttpListener ();
353 listener.Prefixes.Add ("http://127.0.0.1:9001/closewhilebegin/");
355 CallMe cm = new CallMe ();
356 listener.BeginGetContext (cm.Callback, listener);
358 if (false == cm.Event.WaitOne (3000, false))
359 Assert.Fail ("This should not time out.");
360 Assert.IsNotNull (cm.Error);
361 Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
366 public void AbortWhileBegin ()
368 HttpListener listener = new HttpListener ();
369 listener.Prefixes.Add ("http://127.0.0.1:9001/abortwhilebegin/");
371 CallMe cm = new CallMe ();
372 listener.BeginGetContext (cm.Callback, listener);
374 if (false == cm.Event.WaitOne (3000, false))
375 Assert.Fail ("This should not time out.");
376 Assert.IsNotNull (cm.Error);
377 Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
382 [ExpectedException (typeof (HttpListenerException))]
383 public void CloseWhileGet ()
385 // "System.Net.HttpListener Exception : The I/O operation has been aborted
386 // because of either a thread exit or an application request
387 // at System.Net.HttpListener.GetContext()
388 // at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
390 HttpListener listener = new HttpListener ();
391 listener.Prefixes.Add ("http://127.0.0.1:9001/closewhileget/");
393 RunMe rm = new RunMe (1000, new ThreadStart (listener.Close), new object [0]);
395 HttpListenerContext ctx = listener.GetContext ();
399 [ExpectedException (typeof (HttpListenerException))]
400 public void AbortWhileGet ()
402 // "System.Net.HttpListener Exception : The I/O operation has been aborted
403 // because of either a thread exit or an application request
404 // at System.Net.HttpListener.GetContext()
405 // at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
407 HttpListener listener = new HttpListener ();
408 listener.Prefixes.Add ("http://127.0.0.1:9001/abortwhileget/");
410 RunMe rm = new RunMe (1000, new ThreadStart (listener.Abort), new object [0]);
412 HttpListenerContext ctx = listener.GetContext ();
419 public object Result;
421 public RunMe (int delay_ms, Delegate d, object [] args)
423 this.delay_ms = delay_ms;
430 Thread th = new Thread (new ThreadStart (Run));
436 Thread.Sleep (delay_ms);
437 Result = d.DynamicInvoke (args);
442 public ManualResetEvent Event = new ManualResetEvent (false);
444 public HttpListenerContext Context;
445 public Exception Error;
455 public void Callback (IAsyncResult ares)
459 Error = new ArgumentNullException ("ares");
464 HttpListener listener = (HttpListener) ares.AsyncState;
465 Context = listener.EndGetContext (ares);
466 } catch (Exception e) {
472 public void Dispose ()
479 public void ConnectionReuse ()
481 var uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
483 HttpListener listener = new HttpListener ();
484 listener.Prefixes.Add (uri);
487 IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri);
489 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1");
490 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2");
493 public IPEndPoint CreateListenerRequest (HttpListener listener, string uri)
495 IPEndPoint ipEndPoint = null;
496 listener.BeginGetContext ((result) => ipEndPoint = ListenerCallback (result), listener);
498 var request = (HttpWebRequest) WebRequest.Create (uri);
499 request.Method = "POST";
501 // We need to write something
502 request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1);
503 request.GetRequestStream ().Dispose ();
505 // Send request, socket is created or reused.
506 var response = request.GetResponse ();
508 // Close response so socket can be reused.
514 public static IPEndPoint ListenerCallback (IAsyncResult result)
516 var listener = (HttpListener) result.AsyncState;
517 var context = listener.EndGetContext (result);
518 var clientEndPoint = context.Request.RemoteEndPoint;
520 // Disposing InputStream should not avoid socket reuse
521 context.Request.InputStream.Dispose ();
523 // Close OutputStream to send response
524 context.Response.OutputStream.Close ();
526 return clientEndPoint;