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.
32 using System.Net.Sockets;
33 using System.Threading;
34 using System.Threading.Tasks;
35 using NUnit.Framework;
36 using MonoTests.Helpers;
38 namespace MonoTests.System.Net {
40 public class HttpListenerTest {
44 get { return _port ?? (_port = NetworkHelpers.FindFreePort ()).Value; }
48 #if FEATURE_NO_BSD_SOCKETS
49 [ExpectedException (typeof (PlatformNotSupportedException))]
51 public void DefaultProperties ()
53 HttpListener listener = new HttpListener ();
54 Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
55 Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
56 Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
57 Assert.AreEqual (false, listener.IsListening, "#03");
58 Assert.AreEqual (0, listener.Prefixes.Count, "#04");
59 Assert.AreEqual (null, listener.Realm, "#05");
60 Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
64 #if FEATURE_NO_BSD_SOCKETS
65 [ExpectedException (typeof (PlatformNotSupportedException))]
69 HttpListener listener = new HttpListener ();
74 #if FEATURE_NO_BSD_SOCKETS
75 [ExpectedException (typeof (PlatformNotSupportedException))]
79 HttpListener listener = new HttpListener ();
84 #if FEATURE_NO_BSD_SOCKETS
85 [ExpectedException (typeof (PlatformNotSupportedException))]
87 [ExpectedException (typeof (InvalidOperationException))]
89 public void GetContext1 ()
91 HttpListener listener = new HttpListener ();
92 // "Please call Start () before calling this method"
93 listener.GetContext ();
97 #if FEATURE_NO_BSD_SOCKETS
98 [ExpectedException (typeof (PlatformNotSupportedException))]
100 [ExpectedException (typeof (InvalidOperationException))]
102 public void GetContext2 ()
104 HttpListener listener = new HttpListener ();
106 // "Please call AddPrefix () before calling this method"
107 listener.GetContext ();
111 #if FEATURE_NO_BSD_SOCKETS
112 [ExpectedException (typeof (PlatformNotSupportedException))]
114 [ExpectedException (typeof (InvalidOperationException))]
116 public void BeginGetContext1 ()
118 HttpListener listener = new HttpListener ();
119 // "Please call Start () before calling this method"
120 listener.BeginGetContext (null, null);
124 #if FEATURE_NO_BSD_SOCKETS
125 [ExpectedException (typeof (PlatformNotSupportedException))]
127 public void BeginGetContext2 ()
129 HttpListener listener = new HttpListener ();
131 // One would expect this to fail as BeginGetContext1 does not fail and
132 // calling EndGetContext will wait forever.
133 // Lame. They should check that we have no prefixes.
134 IAsyncResult ares = listener.BeginGetContext (null, null);
135 Assert.IsFalse (ares.IsCompleted);
138 private bool CanOpenPort(int port)
142 using(Socket socket = new Socket (AddressFamily.InterNetwork,
146 socket.Bind (new IPEndPoint (IPAddress.Loopback, port));
151 //Can be AccessDeniedException(ports 80/443 need root access) or
152 //SocketException because other application is listening
159 #if FEATURE_NO_BSD_SOCKETS
160 [ExpectedException (typeof (PlatformNotSupportedException))]
162 public void DefaultHttpPort ()
164 if (!CanOpenPort (80))
165 Assert.Ignore ("Can not open port 80 skipping test.");
166 using(HttpListener listener = new HttpListener ())
168 listener.Prefixes.Add ("http://127.0.0.1/");
170 Assert.IsFalse (CanOpenPort (80), "HttpListener is not listening on port 80.");
175 #if FEATURE_NO_BSD_SOCKETS
176 [ExpectedException (typeof (PlatformNotSupportedException))]
178 public void DefaultHttpsPort ()
180 if (!CanOpenPort (443))
181 Assert.Ignore ("Can not open port 443 skipping test.");
182 using(HttpListener listener = new HttpListener ())
184 listener.Prefixes.Add ("https://127.0.0.1/");
186 Assert.IsFalse (CanOpenPort (443), "HttpListener is not listening on port 443.");
191 #if FEATURE_NO_BSD_SOCKETS
192 [ExpectedException (typeof (PlatformNotSupportedException))]
194 public void TwoListeners_SameAddress ()
196 if (!CanOpenPort (port))
197 Assert.Ignore ("port");
198 HttpListener listener1 = new HttpListener ();
199 listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/");
200 HttpListener listener2 = new HttpListener ();
201 listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
207 #if FEATURE_NO_BSD_SOCKETS
208 [ExpectedException (typeof (PlatformNotSupportedException))]
210 [ExpectedException (typeof (HttpListenerException))]
212 public void TwoListeners_SameURL ()
214 if (!CanOpenPort (port))
215 Assert.Ignore ("port");
216 HttpListener listener1 = new HttpListener ();
217 listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
218 HttpListener listener2 = new HttpListener ();
219 listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
225 #if FEATURE_NO_BSD_SOCKETS
226 [ExpectedException (typeof (PlatformNotSupportedException))]
228 [ExpectedException (typeof (HttpListenerException))]
230 public void MultipleSlashes ()
232 if (!CanOpenPort (port))
233 Assert.Ignore ("port");
234 HttpListener listener = new HttpListener ();
235 listener.Prefixes.Add ("http://localhost:" + port + "/hola////");
236 // this one throws on Start(), not when adding it.
241 #if FEATURE_NO_BSD_SOCKETS
242 [ExpectedException (typeof (PlatformNotSupportedException))]
244 [ExpectedException (typeof (HttpListenerException))]
246 public void PercentSign ()
248 if (!CanOpenPort (port))
249 Assert.Ignore ("port");
250 HttpListener listener = new HttpListener ();
251 listener.Prefixes.Add ("http://localhost:" + port + "/hola%3E/");
252 // this one throws on Start(), not when adding it.
257 #if FEATURE_NO_BSD_SOCKETS
258 [ExpectedException (typeof (PlatformNotSupportedException))]
260 public void CloseBeforeStart ()
262 HttpListener listener = new HttpListener ();
267 #if FEATURE_NO_BSD_SOCKETS
268 [ExpectedException (typeof (PlatformNotSupportedException))]
270 public void CloseTwice ()
272 if (!CanOpenPort (port))
273 Assert.Ignore ("port");
274 HttpListener listener = new HttpListener ();
275 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
282 #if FEATURE_NO_BSD_SOCKETS
283 [ExpectedException (typeof (PlatformNotSupportedException))]
285 public void StartStopStart ()
287 if (!CanOpenPort (port))
288 Assert.Ignore ("port");
289 HttpListener listener = new HttpListener ();
290 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
298 #if FEATURE_NO_BSD_SOCKETS
299 [ExpectedException (typeof (PlatformNotSupportedException))]
301 public void StartStopDispose ()
303 if (!CanOpenPort (port))
304 Assert.Ignore ("port");
305 using (HttpListener listener = new HttpListener ()){
306 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
313 #if FEATURE_NO_BSD_SOCKETS
314 [ExpectedException (typeof (PlatformNotSupportedException))]
316 public void AbortBeforeStart ()
318 HttpListener listener = new HttpListener ();
323 #if FEATURE_NO_BSD_SOCKETS
324 [ExpectedException (typeof (PlatformNotSupportedException))]
326 public void AbortTwice ()
328 if (!CanOpenPort (port))
329 Assert.Ignore ("port");
330 HttpListener listener = new HttpListener ();
331 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
338 #if FEATURE_NO_BSD_SOCKETS
339 [ExpectedException (typeof (PlatformNotSupportedException))]
341 public void PropertiesWhenClosed1 ()
343 HttpListener listener = new HttpListener ();
345 Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
346 Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
347 Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
348 Assert.AreEqual (false, listener.IsListening, "#03");
349 Assert.AreEqual (null, listener.Realm, "#05");
350 Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
354 #if FEATURE_NO_BSD_SOCKETS
355 [ExpectedException (typeof (PlatformNotSupportedException))]
357 [ExpectedException (typeof (ObjectDisposedException))]
359 public void PropertiesWhenClosed2 ()
361 HttpListener listener = new HttpListener ();
363 HttpListenerPrefixCollection p = listener.Prefixes;
367 #if FEATURE_NO_BSD_SOCKETS
368 [ExpectedException (typeof (PlatformNotSupportedException))]
370 [ExpectedException (typeof (ObjectDisposedException))]
372 public void PropertiesWhenClosedSet1 ()
374 HttpListener listener = new HttpListener ();
376 listener.AuthenticationSchemes = AuthenticationSchemes.None;
380 #if FEATURE_NO_BSD_SOCKETS
381 [ExpectedException (typeof (PlatformNotSupportedException))]
383 [ExpectedException (typeof (ObjectDisposedException))]
385 public void PropertiesWhenClosedSet2 ()
387 HttpListener listener = new HttpListener ();
389 listener.AuthenticationSchemeSelectorDelegate = null;
393 #if FEATURE_NO_BSD_SOCKETS
394 [ExpectedException (typeof (PlatformNotSupportedException))]
396 [ExpectedException (typeof (ObjectDisposedException))]
398 public void PropertiesWhenClosedSet3 ()
400 HttpListener listener = new HttpListener ();
402 listener.IgnoreWriteExceptions = true;
406 #if FEATURE_NO_BSD_SOCKETS
407 [ExpectedException (typeof (PlatformNotSupportedException))]
409 [ExpectedException (typeof (ObjectDisposedException))]
411 public void PropertiesWhenClosedSet4 ()
413 HttpListener listener = new HttpListener ();
415 listener.Realm = "hola";
419 #if FEATURE_NO_BSD_SOCKETS
420 [ExpectedException (typeof (PlatformNotSupportedException))]
422 [ExpectedException (typeof (ObjectDisposedException))]
424 public void PropertiesWhenClosedSet5 ()
426 HttpListener listener = new HttpListener ();
428 listener.UnsafeConnectionNtlmAuthentication = true;
432 #if FEATURE_NO_BSD_SOCKETS
433 [ExpectedException (typeof (PlatformNotSupportedException))]
435 public void PropertiesWhenClosed3 ()
437 HttpListener listener = new HttpListener ();
439 Assert.IsFalse (listener.IsListening);
443 #if FEATURE_NO_BSD_SOCKETS
444 [ExpectedException (typeof (PlatformNotSupportedException))]
446 public void CloseWhileBegin ()
448 HttpListener listener = new HttpListener ();
449 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/closewhilebegin/");
451 CallMe cm = new CallMe ();
452 listener.BeginGetContext (cm.Callback, listener);
454 if (false == cm.Event.WaitOne (3000, false))
455 Assert.Fail ("This should not time out.");
456 Assert.IsNotNull (cm.Error);
457 Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
462 #if FEATURE_NO_BSD_SOCKETS
463 [ExpectedException (typeof (PlatformNotSupportedException))]
465 public void AbortWhileBegin ()
467 HttpListener listener = new HttpListener ();
468 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/abortwhilebegin/");
470 CallMe cm = new CallMe ();
471 listener.BeginGetContext (cm.Callback, listener);
473 if (false == cm.Event.WaitOne (3000, false))
474 Assert.Fail ("This should not time out.");
475 Assert.IsNotNull (cm.Error);
476 Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
481 #if FEATURE_NO_BSD_SOCKETS
482 [ExpectedException (typeof (PlatformNotSupportedException))]
484 [ExpectedException (typeof (HttpListenerException))]
486 public void CloseWhileGet ()
488 // "System.Net.HttpListener Exception : The I/O operation has been aborted
489 // because of either a thread exit or an application request
490 // at System.Net.HttpListener.GetContext()
491 // at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
493 HttpListener listener = new HttpListener ();
494 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/closewhileget/");
496 RunMe rm = new RunMe (1000, new ThreadStart (listener.Close), new object [0]);
498 HttpListenerContext ctx = listener.GetContext ();
502 #if FEATURE_NO_BSD_SOCKETS
503 [ExpectedException (typeof (PlatformNotSupportedException))]
505 [ExpectedException (typeof (HttpListenerException))]
507 public void AbortWhileGet ()
509 // "System.Net.HttpListener Exception : The I/O operation has been aborted
510 // because of either a thread exit or an application request
511 // at System.Net.HttpListener.GetContext()
512 // at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
514 HttpListener listener = new HttpListener ();
515 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/abortwhileget/");
517 RunMe rm = new RunMe (1000, new ThreadStart (listener.Abort), new object [0]);
519 HttpListenerContext ctx = listener.GetContext ();
526 public object Result;
528 public RunMe (int delay_ms, Delegate d, object [] args)
530 this.delay_ms = delay_ms;
537 Thread th = new Thread (new ThreadStart (Run));
543 Thread.Sleep (delay_ms);
544 Result = d.DynamicInvoke (args);
549 public ManualResetEvent Event = new ManualResetEvent (false);
551 public HttpListenerContext Context;
552 public Exception Error;
562 public void Callback (IAsyncResult ares)
566 Error = new ArgumentNullException ("ares");
571 HttpListener listener = (HttpListener) ares.AsyncState;
572 Context = listener.EndGetContext (ares);
573 } catch (Exception e) {
579 public void Dispose ()
586 #if FEATURE_NO_BSD_SOCKETS
587 [ExpectedException (typeof (PlatformNotSupportedException))]
589 public void ConnectionReuse ()
591 var uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
593 HttpListener listener = new HttpListener ();
594 listener.Prefixes.Add (uri);
597 IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri);
599 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1");
600 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2");
603 public IPEndPoint CreateListenerRequest (HttpListener listener, string uri)
605 IPEndPoint ipEndPoint = null;
606 var mre = new ManualResetEventSlim ();
607 listener.BeginGetContext (result => {
608 ipEndPoint = ListenerCallback (result);
612 var request = (HttpWebRequest) WebRequest.Create (uri);
613 request.Method = "POST";
615 // We need to write something
616 request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1);
617 request.GetRequestStream ().Dispose ();
619 // Send request, socket is created or reused.
620 var response = request.GetResponse ();
622 // Close response so socket can be reused.
630 public static IPEndPoint ListenerCallback (IAsyncResult result)
632 var listener = (HttpListener) result.AsyncState;
633 var context = listener.EndGetContext (result);
634 var clientEndPoint = context.Request.RemoteEndPoint;
636 // Disposing InputStream should not avoid socket reuse
637 context.Request.InputStream.Dispose ();
639 // Close OutputStream to send response
640 context.Response.OutputStream.Close ();
642 return clientEndPoint;
646 #if FEATURE_NO_BSD_SOCKETS
647 [ExpectedException (typeof (PlatformNotSupportedException))]
649 public void UserHeaderWithDoubleMultiValue ()
651 string uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
653 var l = new HttpListener ();
654 l.Prefixes.Add (uri);
656 l.BeginGetContext (ar => {
657 var ctx = l.EndGetContext (ar);
659 var response = ctx.Response;
660 response.Headers.Add ("X-Custom-Header", "A");
661 response.Headers.Add ("X-Custom-Header", "B");
666 HttpWebRequest wr = HttpWebRequest.CreateHttp (uri);
667 var resp = wr.GetResponse ();
668 var vls = resp.Headers.GetValues ("X-Custom-Header");
670 Assert.AreEqual (2, vls.Length);
676 #if FEATURE_NO_BSD_SOCKETS
677 [ExpectedException (typeof (PlatformNotSupportedException))]
679 public void HttpClientIsDisconnectedCheckForWriteException()
681 string uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
683 AutoResetEvent exceptionOccuredEvent = new AutoResetEvent (false);
684 HttpListener listener = new HttpListener {
685 IgnoreWriteExceptions = false
687 listener.Prefixes.Add (uri);
689 listener.BeginGetContext (result =>
691 HttpListenerContext context = listener.EndGetContext (result);
692 context.Response.SendChunked = true;
693 context.Request.InputStream.Close ();
695 var bytes = new byte [1024];
696 using(Stream outputStream = context.Response.OutputStream) {
699 outputStream.Write (bytes, 0, bytes.Length);
701 exceptionOccuredEvent.Set ();
706 Task.Factory.StartNew (() =>
708 var webRequest = (HttpWebRequest)WebRequest.Create (uri);
709 webRequest.Method = "POST";
710 webRequest.KeepAlive = false;
711 Stream requestStream = webRequest.GetRequestStream ();
712 requestStream.WriteByte (1);
713 requestStream.Close ();
714 using (WebResponse response = webRequest.GetResponse ())
715 using (Stream stream = response.GetResponseStream ()) {
716 byte[] clientBytes = new byte [1024];
717 Assert.IsNotNull (stream, "#01");
718 stream.Read (clientBytes, 0, clientBytes.Length);
722 Assert.IsTrue (exceptionOccuredEvent.WaitOne (15 * 1000), "#02");