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 public void Teardown ()
54 #if FEATURE_NO_BSD_SOCKETS
55 [ExpectedException (typeof (PlatformNotSupportedException))]
57 public void DefaultProperties ()
59 HttpListener listener = new HttpListener ();
60 Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
61 Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
62 Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
63 Assert.AreEqual (false, listener.IsListening, "#03");
64 Assert.AreEqual (0, listener.Prefixes.Count, "#04");
65 Assert.AreEqual (null, listener.Realm, "#05");
66 Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
70 #if FEATURE_NO_BSD_SOCKETS
71 [ExpectedException (typeof (PlatformNotSupportedException))]
75 HttpListener listener = new HttpListener ();
80 #if FEATURE_NO_BSD_SOCKETS
81 [ExpectedException (typeof (PlatformNotSupportedException))]
85 HttpListener listener = new HttpListener ();
90 #if FEATURE_NO_BSD_SOCKETS
91 [ExpectedException (typeof (PlatformNotSupportedException))]
93 [ExpectedException (typeof (InvalidOperationException))]
95 public void GetContext1 ()
97 HttpListener listener = new HttpListener ();
98 // "Please call Start () before calling this method"
99 listener.GetContext ();
103 #if FEATURE_NO_BSD_SOCKETS
104 [ExpectedException (typeof (PlatformNotSupportedException))]
106 [ExpectedException (typeof (InvalidOperationException))]
108 public void GetContext2 ()
110 HttpListener listener = new HttpListener ();
112 // "Please call AddPrefix () before calling this method"
113 listener.GetContext ();
117 #if FEATURE_NO_BSD_SOCKETS
118 [ExpectedException (typeof (PlatformNotSupportedException))]
120 [ExpectedException (typeof (InvalidOperationException))]
122 public void BeginGetContext1 ()
124 HttpListener listener = new HttpListener ();
125 // "Please call Start () before calling this method"
126 listener.BeginGetContext (null, null);
130 #if FEATURE_NO_BSD_SOCKETS
131 [ExpectedException (typeof (PlatformNotSupportedException))]
133 public void BeginGetContext2 ()
135 HttpListener listener = new HttpListener ();
137 // One would expect this to fail as BeginGetContext1 does not fail and
138 // calling EndGetContext will wait forever.
139 // Lame. They should check that we have no prefixes.
140 IAsyncResult ares = listener.BeginGetContext (null, null);
141 Assert.IsFalse (ares.IsCompleted);
144 private bool CanOpenPort(int port)
148 using(Socket socket = new Socket (AddressFamily.InterNetwork,
152 socket.Bind (new IPEndPoint (IPAddress.Loopback, port));
157 //Can be AccessDeniedException(ports 80/443 need root access) or
158 //SocketException because other application is listening
165 #if FEATURE_NO_BSD_SOCKETS
166 [ExpectedException (typeof (PlatformNotSupportedException))]
168 public void DefaultHttpPort ()
170 if (!CanOpenPort (80))
171 Assert.Ignore ("Can not open port 80 skipping test.");
172 using(HttpListener listener = new HttpListener ())
174 listener.Prefixes.Add ("http://127.0.0.1/");
176 Assert.IsFalse (CanOpenPort (80), "HttpListener is not listening on port 80.");
181 #if FEATURE_NO_BSD_SOCKETS
182 [ExpectedException (typeof (PlatformNotSupportedException))]
184 public void DefaultHttpsPort ()
186 if (!CanOpenPort (443))
187 Assert.Ignore ("Can not open port 443 skipping test.");
188 using(HttpListener listener = new HttpListener ())
190 listener.Prefixes.Add ("https://127.0.0.1/");
192 Assert.IsFalse (CanOpenPort (443), "HttpListener is not listening on port 443.");
197 #if FEATURE_NO_BSD_SOCKETS
198 [ExpectedException (typeof (PlatformNotSupportedException))]
200 public void TwoListeners_SameAddress ()
202 if (!CanOpenPort (port))
203 Assert.Ignore ("port");
204 HttpListener listener1 = new HttpListener ();
205 listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/");
206 HttpListener listener2 = new HttpListener ();
207 listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
213 #if FEATURE_NO_BSD_SOCKETS
214 [ExpectedException (typeof (PlatformNotSupportedException))]
216 [ExpectedException (typeof (HttpListenerException))]
218 public void TwoListeners_SameURL ()
220 if (!CanOpenPort (port))
221 Assert.Ignore ("port");
222 HttpListener listener1 = new HttpListener ();
223 listener1.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
224 HttpListener listener2 = new HttpListener ();
225 listener2.Prefixes.Add ("http://127.0.0.1:" + port + "/hola/");
231 #if FEATURE_NO_BSD_SOCKETS
232 [ExpectedException (typeof (PlatformNotSupportedException))]
234 [ExpectedException (typeof (HttpListenerException))]
236 public void MultipleSlashes ()
238 if (!CanOpenPort (port))
239 Assert.Ignore ("port");
240 HttpListener listener = new HttpListener ();
241 listener.Prefixes.Add ("http://localhost:" + port + "/hola////");
242 // this one throws on Start(), not when adding it.
247 #if FEATURE_NO_BSD_SOCKETS
248 [ExpectedException (typeof (PlatformNotSupportedException))]
250 [ExpectedException (typeof (HttpListenerException))]
252 public void PercentSign ()
254 if (!CanOpenPort (port))
255 Assert.Ignore ("port");
256 HttpListener listener = new HttpListener ();
257 listener.Prefixes.Add ("http://localhost:" + port + "/hola%3E/");
258 // this one throws on Start(), not when adding it.
263 #if FEATURE_NO_BSD_SOCKETS
264 [ExpectedException (typeof (PlatformNotSupportedException))]
266 public void CloseBeforeStart ()
268 HttpListener listener = new HttpListener ();
273 #if FEATURE_NO_BSD_SOCKETS
274 [ExpectedException (typeof (PlatformNotSupportedException))]
276 public void CloseTwice ()
278 if (!CanOpenPort (port))
279 Assert.Ignore ("port");
280 HttpListener listener = new HttpListener ();
281 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
288 #if FEATURE_NO_BSD_SOCKETS
289 [ExpectedException (typeof (PlatformNotSupportedException))]
291 public void StartStopStart ()
293 if (!CanOpenPort (port))
294 Assert.Ignore ("port");
295 HttpListener listener = new HttpListener ();
296 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
304 #if FEATURE_NO_BSD_SOCKETS
305 [ExpectedException (typeof (PlatformNotSupportedException))]
307 public void StartStopDispose ()
309 if (!CanOpenPort (port))
310 Assert.Ignore ("port");
311 using (HttpListener listener = new HttpListener ()){
312 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
319 #if FEATURE_NO_BSD_SOCKETS
320 [ExpectedException (typeof (PlatformNotSupportedException))]
322 public void AbortBeforeStart ()
324 HttpListener listener = new HttpListener ();
329 #if FEATURE_NO_BSD_SOCKETS
330 [ExpectedException (typeof (PlatformNotSupportedException))]
332 public void AbortTwice ()
334 if (!CanOpenPort (port))
335 Assert.Ignore ("port");
336 HttpListener listener = new HttpListener ();
337 listener.Prefixes.Add ("http://localhost:" + port + "/hola/");
344 #if FEATURE_NO_BSD_SOCKETS
345 [ExpectedException (typeof (PlatformNotSupportedException))]
347 public void PropertiesWhenClosed1 ()
349 HttpListener listener = new HttpListener ();
351 Assert.AreEqual (AuthenticationSchemes.Anonymous, listener.AuthenticationSchemes, "#01");
352 Assert.AreEqual (null, listener.AuthenticationSchemeSelectorDelegate, "#02");
353 Assert.AreEqual (false, listener.IgnoreWriteExceptions, "#03");
354 Assert.AreEqual (false, listener.IsListening, "#03");
355 Assert.AreEqual (null, listener.Realm, "#05");
356 Assert.AreEqual (false, listener.UnsafeConnectionNtlmAuthentication, "#06");
360 #if FEATURE_NO_BSD_SOCKETS
361 [ExpectedException (typeof (PlatformNotSupportedException))]
363 [ExpectedException (typeof (ObjectDisposedException))]
365 public void PropertiesWhenClosed2 ()
367 HttpListener listener = new HttpListener ();
369 HttpListenerPrefixCollection p = listener.Prefixes;
373 #if FEATURE_NO_BSD_SOCKETS
374 [ExpectedException (typeof (PlatformNotSupportedException))]
376 [ExpectedException (typeof (ObjectDisposedException))]
378 public void PropertiesWhenClosedSet1 ()
380 HttpListener listener = new HttpListener ();
382 listener.AuthenticationSchemes = AuthenticationSchemes.None;
386 #if FEATURE_NO_BSD_SOCKETS
387 [ExpectedException (typeof (PlatformNotSupportedException))]
389 [ExpectedException (typeof (ObjectDisposedException))]
391 public void PropertiesWhenClosedSet2 ()
393 HttpListener listener = new HttpListener ();
395 listener.AuthenticationSchemeSelectorDelegate = null;
399 #if FEATURE_NO_BSD_SOCKETS
400 [ExpectedException (typeof (PlatformNotSupportedException))]
402 [ExpectedException (typeof (ObjectDisposedException))]
404 public void PropertiesWhenClosedSet3 ()
406 HttpListener listener = new HttpListener ();
408 listener.IgnoreWriteExceptions = true;
412 #if FEATURE_NO_BSD_SOCKETS
413 [ExpectedException (typeof (PlatformNotSupportedException))]
415 [ExpectedException (typeof (ObjectDisposedException))]
417 public void PropertiesWhenClosedSet4 ()
419 HttpListener listener = new HttpListener ();
421 listener.Realm = "hola";
425 #if FEATURE_NO_BSD_SOCKETS
426 [ExpectedException (typeof (PlatformNotSupportedException))]
428 [ExpectedException (typeof (ObjectDisposedException))]
430 public void PropertiesWhenClosedSet5 ()
432 HttpListener listener = new HttpListener ();
434 listener.UnsafeConnectionNtlmAuthentication = true;
438 #if FEATURE_NO_BSD_SOCKETS
439 [ExpectedException (typeof (PlatformNotSupportedException))]
441 public void PropertiesWhenClosed3 ()
443 HttpListener listener = new HttpListener ();
445 Assert.IsFalse (listener.IsListening);
449 #if FEATURE_NO_BSD_SOCKETS
450 [ExpectedException (typeof (PlatformNotSupportedException))]
452 public void CloseWhileBegin ()
454 HttpListener listener = new HttpListener ();
455 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/closewhilebegin/");
457 CallMe cm = new CallMe ();
458 listener.BeginGetContext (cm.Callback, listener);
460 if (false == cm.Event.WaitOne (3000, false))
461 Assert.Fail ("This should not time out.");
462 Assert.IsNotNull (cm.Error);
463 Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
468 #if FEATURE_NO_BSD_SOCKETS
469 [ExpectedException (typeof (PlatformNotSupportedException))]
471 public void AbortWhileBegin ()
473 HttpListener listener = new HttpListener ();
474 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/abortwhilebegin/");
476 CallMe cm = new CallMe ();
477 listener.BeginGetContext (cm.Callback, listener);
479 if (false == cm.Event.WaitOne (3000, false))
480 Assert.Fail ("This should not time out.");
481 Assert.IsNotNull (cm.Error);
482 Assert.AreEqual (typeof (ObjectDisposedException), cm.Error.GetType (), "Exception type");
487 #if FEATURE_NO_BSD_SOCKETS
488 [ExpectedException (typeof (PlatformNotSupportedException))]
490 [ExpectedException (typeof (HttpListenerException))]
492 public void CloseWhileGet ()
494 // "System.Net.HttpListener Exception : The I/O operation has been aborted
495 // because of either a thread exit or an application request
496 // at System.Net.HttpListener.GetContext()
497 // at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
499 HttpListener listener = new HttpListener ();
500 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/closewhileget/");
502 RunMe rm = new RunMe (1000, new ThreadStart (listener.Close), new object [0]);
504 HttpListenerContext ctx = listener.GetContext ();
508 #if FEATURE_NO_BSD_SOCKETS
509 [ExpectedException (typeof (PlatformNotSupportedException))]
511 [ExpectedException (typeof (HttpListenerException))]
513 public void AbortWhileGet ()
515 // "System.Net.HttpListener Exception : The I/O operation has been aborted
516 // because of either a thread exit or an application request
517 // at System.Net.HttpListener.GetContext()
518 // at MonoTests.System.Net.HttpListenerTest.CloseWhileGet()
520 HttpListener listener = new HttpListener ();
521 listener.Prefixes.Add ("http://127.0.0.1:" + NetworkHelpers.FindFreePort () + "/abortwhileget/");
523 RunMe rm = new RunMe (1000, new ThreadStart (listener.Abort), new object [0]);
525 HttpListenerContext ctx = listener.GetContext ();
532 public object Result;
534 public RunMe (int delay_ms, Delegate d, object [] args)
536 this.delay_ms = delay_ms;
543 Thread th = new Thread (new ThreadStart (Run));
549 Thread.Sleep (delay_ms);
550 Result = d.DynamicInvoke (args);
555 public ManualResetEvent Event = new ManualResetEvent (false);
557 public HttpListenerContext Context;
558 public Exception Error;
568 public void Callback (IAsyncResult ares)
572 Error = new ArgumentNullException ("ares");
577 HttpListener listener = (HttpListener) ares.AsyncState;
578 Context = listener.EndGetContext (ares);
579 } catch (Exception e) {
585 public void Dispose ()
592 #if FEATURE_NO_BSD_SOCKETS
593 [ExpectedException (typeof (PlatformNotSupportedException))]
595 public void ConnectionReuse ()
597 var uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
599 HttpListener listener = new HttpListener ();
600 listener.Prefixes.Add (uri);
603 IPEndPoint expectedIpEndPoint = CreateListenerRequest (listener, uri);
605 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse1");
606 Assert.AreEqual (expectedIpEndPoint, CreateListenerRequest (listener, uri), "reuse2");
609 public IPEndPoint CreateListenerRequest (HttpListener listener, string uri)
611 IPEndPoint ipEndPoint = null;
612 var mre = new ManualResetEventSlim ();
613 listener.BeginGetContext (result => {
614 ipEndPoint = ListenerCallback (result);
618 var request = (HttpWebRequest) WebRequest.Create (uri);
619 request.Method = "POST";
621 // We need to write something
622 request.GetRequestStream ().Write (new byte [] {(byte)'a'}, 0, 1);
623 request.GetRequestStream ().Dispose ();
625 // Send request, socket is created or reused.
626 var response = request.GetResponse ();
628 // Close response so socket can be reused.
636 public static IPEndPoint ListenerCallback (IAsyncResult result)
638 var listener = (HttpListener) result.AsyncState;
639 var context = listener.EndGetContext (result);
640 var clientEndPoint = context.Request.RemoteEndPoint;
642 // Disposing InputStream should not avoid socket reuse
643 context.Request.InputStream.Dispose ();
645 // Close OutputStream to send response
646 context.Response.OutputStream.Close ();
648 return clientEndPoint;
652 #if FEATURE_NO_BSD_SOCKETS
653 [ExpectedException (typeof (PlatformNotSupportedException))]
655 public void UserHeaderWithDoubleMultiValue ()
657 string uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
659 var l = new HttpListener ();
660 l.Prefixes.Add (uri);
662 l.BeginGetContext (ar => {
663 var ctx = l.EndGetContext (ar);
665 var response = ctx.Response;
666 response.Headers.Add ("X-Custom-Header", "A");
667 response.Headers.Add ("X-Custom-Header", "B");
672 HttpWebRequest wr = HttpWebRequest.CreateHttp (uri);
673 var resp = wr.GetResponse ();
674 var vls = resp.Headers.GetValues ("X-Custom-Header");
676 Assert.AreEqual (2, vls.Length);
682 #if FEATURE_NO_BSD_SOCKETS
683 [ExpectedException (typeof (PlatformNotSupportedException))]
685 public void HttpClientIsDisconnectedCheckForWriteException()
687 string uri = "http://localhost:" + NetworkHelpers.FindFreePort () + "/";
689 AutoResetEvent exceptionOccuredEvent = new AutoResetEvent (false);
690 HttpListener listener = new HttpListener {
691 IgnoreWriteExceptions = false
693 listener.Prefixes.Add (uri);
695 listener.BeginGetContext (result =>
697 HttpListenerContext context = listener.EndGetContext (result);
698 context.Response.SendChunked = true;
699 context.Request.InputStream.Close ();
701 var bytes = new byte [1024];
702 using(Stream outputStream = context.Response.OutputStream) {
705 outputStream.Write (bytes, 0, bytes.Length);
707 exceptionOccuredEvent.Set ();
712 Task.Factory.StartNew (() =>
714 var webRequest = (HttpWebRequest)WebRequest.Create (uri);
715 webRequest.Method = "POST";
716 webRequest.KeepAlive = false;
717 Stream requestStream = webRequest.GetRequestStream ();
718 requestStream.WriteByte (1);
719 requestStream.Close ();
720 using (WebResponse response = webRequest.GetResponse ())
721 using (Stream stream = response.GetResponseStream ()) {
722 byte[] clientBytes = new byte [1024];
723 Assert.IsNotNull (stream, "#01");
724 stream.Read (clientBytes, 0, clientBytes.Length);
728 Assert.IsTrue (exceptionOccuredEvent.WaitOne (15 * 1000), "#02");