[System*] Throw a PlatformNotSupported exception when using the networking stack...
[mono.git] / mcs / class / System / Test / System.Net / HttpListener2Test.cs
1 //
2 // HttpListener2Test.cs
3 //      - Unit tests for System.Net.HttpListener - connection testing
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
30 using System;
31 using System.Collections.Generic;
32 using System.Globalization;
33 using System.IO;
34 using System.Net;
35 using System.Net.Sockets;
36 using System.Text;
37 using System.Threading;
38
39 using NUnit.Framework;
40
41 using MonoTests.Helpers;
42
43 // ***************************************************************************************
44 // NOTE: when adding prefixes, make then unique per test, as MS might take 'some time' to
45 // unregister it even after explicitly closing the listener.
46 // ***************************************************************************************
47 namespace MonoTests.System.Net {
48         
49         [TestFixture]
50         public class HttpListener2Test {
51                 
52                 private HttpListener _listener = null;
53                 
54                 public class MyNetworkStream : NetworkStream {
55                         public MyNetworkStream (Socket sock) : base (sock, true)
56                         {
57                         }
58
59                         public Socket GetSocket ()
60                         {
61                                 return Socket;
62                         }
63                 }
64
65                 public static HttpListener CreateAndStartListener (string prefix)
66                 {
67                         HttpListener listener = new HttpListener ();
68                         listener.Prefixes.Add (prefix);
69                         listener.Start ();
70                         return listener;
71                 }
72
73                 public static HttpListener CreateAndStartListener (string prefix, AuthenticationSchemes authSchemes)
74                 {
75                         HttpListener listener = new HttpListener ();
76                         listener.AuthenticationSchemes = authSchemes;
77                         listener.Prefixes.Add (prefix);
78                         listener.Start ();
79                         return listener;
80                 }
81
82                 public static MyNetworkStream CreateNS (int port)
83                 {
84                         return CreateNS (IPAddress.Loopback, port, 5000);
85                 }
86
87                 public static MyNetworkStream CreateNS (int port, int timeout_ms)
88                 {
89                         return CreateNS (IPAddress.Loopback, port, timeout_ms);
90                 }
91
92                 public static MyNetworkStream CreateNS (IPAddress ip, int port)
93                 {
94                         return CreateNS (ip, port, 5000);
95                 }
96
97                 public static MyNetworkStream CreateNS (IPAddress ip, int port, int timeout_ms)
98                 {
99                         Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
100                         sock.Connect (new IPEndPoint (ip, port));
101                         sock.SendTimeout = timeout_ms;
102                         sock.ReceiveTimeout = timeout_ms;
103                         return new MyNetworkStream (sock);
104                 }
105
106                 public static void Send (Stream stream, string str)
107                 {
108                         byte [] bytes = Encoding.ASCII.GetBytes (str);
109                         stream.Write (bytes, 0, bytes.Length);
110                 }
111
112                 public static string Receive (Stream stream, int size)
113                 {
114                         byte [] bytes = new byte [size];
115                         int nread = stream.Read (bytes, 0, size);
116                         return Encoding.ASCII.GetString (bytes, 0, nread);
117                 }
118
119                 public static string ReceiveWithTimeout (Stream stream, int size, int timeout, out bool timed_out)
120                 {
121                         byte [] bytes = new byte [size];
122                         IAsyncResult ares = stream.BeginRead (bytes, 0, size, null, null);
123                         timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
124                         if (timed_out)
125                                 return null;
126                         int nread = stream.EndRead (ares);
127                         return Encoding.ASCII.GetString (bytes, 0, nread);
128                 }
129
130                 public static HttpListenerContext GetContextWithTimeout (HttpListener listener, int timeout, out bool timed_out)
131                 {
132                         IAsyncResult ares = listener.BeginGetContext (null, null);
133                         timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
134                         if (timed_out) 
135                                 return null;
136                         return listener.EndGetContext (ares);
137                 }
138                 
139                 [TearDown] 
140                 public void Dispose()
141                 {
142                         if (_listener != null) {
143                                 _listener.Close();
144                                 _listener = null;
145                         }
146                 }
147
148                 [Test]
149 #if FEATURE_NO_BSD_SOCKETS
150                 [ExpectedException (typeof (PlatformNotSupportedException))]
151 #endif
152                 public void Test1 ()
153                 {
154                         var port = NetworkHelpers.FindFreePort ();
155                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test1/");
156                         NetworkStream ns = CreateNS (port);
157                         Send (ns, "GET / HTTP/1.1\r\n\r\n"); // No host
158                         string response = Receive (ns, 512);
159                         ns.Close ();
160                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 400"));
161                 }
162
163                 [Test]
164 #if FEATURE_NO_BSD_SOCKETS
165                 [ExpectedException (typeof (PlatformNotSupportedException))]
166 #endif
167                 public void Test2 ()
168                 {
169                         var port = NetworkHelpers.FindFreePort ();
170                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test2/");
171                         NetworkStream ns = CreateNS (port);
172                         Send (ns, "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"); // no prefix
173                         string response = Receive (ns, 512);
174                         ns.Close ();
175                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 400"));
176                 }
177
178                 [Test]
179 #if FEATURE_NO_BSD_SOCKETS
180                 [ExpectedException (typeof (PlatformNotSupportedException))]
181 #endif
182                 public void Test3 ()
183                 {
184                         StringBuilder bad = new StringBuilder ();
185                         for (int i = 0; i < 33; i++){
186                                 if (i != 13)
187                                         bad.Append ((char) i);
188                         }
189                         bad.Append ('(');
190                         bad.Append (')');
191                         bad.Append ('[');
192                         bad.Append (']');
193                         bad.Append ('<');
194                         bad.Append ('>');
195                         bad.Append ('@');
196                         bad.Append (',');
197                         bad.Append (';');
198                         bad.Append (':');
199                         bad.Append ('\\');
200                         bad.Append ('"');
201                         bad.Append ('/');
202                         bad.Append ('?');
203                         bad.Append ('=');
204                         bad.Append ('{');
205                         bad.Append ('}');
206
207                         foreach (char b in bad.ToString ()){
208                                 var port = NetworkHelpers.FindFreePort ();
209                                 HttpListener listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test3/");
210                                 NetworkStream ns = CreateNS (port);
211                                 Send (ns, String.Format ("MA{0} / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n", b)); // bad method
212                                 
213                                 string response = Receive (ns, 512);
214                                 ns.Close ();
215                                 listener.Close ();
216                                 Assert.IsTrue(response.StartsWith ("HTTP/1.1 400"), String.Format ("Failed on {0}", (int) b));
217                         }
218                 }
219
220                 [Test]
221 #if FEATURE_NO_BSD_SOCKETS
222                 [ExpectedException (typeof (PlatformNotSupportedException))]
223 #endif
224                 public void Test4 ()
225                 {
226                         var port = NetworkHelpers.FindFreePort ();
227                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test4/");
228                         NetworkStream ns = CreateNS (port);
229                         Send (ns, "POST /test4/ HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"); // length required
230                         string response = Receive (ns, 512);
231                         ns.Close ();
232                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 411"));
233                 }
234
235                 [Test]
236 #if FEATURE_NO_BSD_SOCKETS
237                 [ExpectedException (typeof (PlatformNotSupportedException))]
238 #endif
239                 public void Test5 ()
240                 {
241                         var port = NetworkHelpers.FindFreePort ();
242                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test5/");
243                         NetworkStream ns = CreateNS (port);
244                         Send (ns, "POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nTransfer-Encoding: pepe\r\n\r\n"); // not implemented
245                         string response = Receive (ns, 512);
246                         ns.Close ();
247                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 501"));
248                 }
249
250                 [Test]
251 #if FEATURE_NO_BSD_SOCKETS
252                 [ExpectedException (typeof (PlatformNotSupportedException))]
253 #endif
254                 public void Test6 ()
255                 {
256                         var port = NetworkHelpers.FindFreePort ();
257                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test6/");
258                         NetworkStream ns = CreateNS (port);
259                          // not implemented! This is against the RFC. Should be a bad request/length required
260                         Send (ns, "POST /test6/ HTTP/1.1\r\nHost: 127.0.0.1\r\nTransfer-Encoding: identity\r\n\r\n");
261                         string response = Receive (ns, 512);
262                         ns.Close ();
263                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 501"));
264                 }
265
266                 [Test]
267 #if FEATURE_NO_BSD_SOCKETS
268                 [ExpectedException (typeof (PlatformNotSupportedException))]
269 #endif
270                 public void Test7 ()
271                 {
272                         var port = NetworkHelpers.FindFreePort ();
273                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test7/");
274                         NetworkStream ns = CreateNS (port);
275                         Send (ns, "POST /test7/ HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
276                         HttpListenerContext ctx = _listener.GetContext ();
277                         Send (ctx.Response.OutputStream, "%%%OK%%%");
278                         ctx.Response.Close ();
279                         string response = Receive (ns, 1024);
280                         ns.Close ();
281                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 200"));
282                         Assert.IsTrue(response.Contains ("Transfer-Encoding: chunked"));
283                 }
284
285                 [Test]
286 #if FEATURE_NO_BSD_SOCKETS
287                 [ExpectedException (typeof (PlatformNotSupportedException))]
288 #endif
289                 public void Test8 ()
290                 {
291                         var port = NetworkHelpers.FindFreePort ();
292                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test8/");
293                         NetworkStream ns = CreateNS (port);
294                         // Just like Test7, but 1.0
295                         Send (ns, "POST /test8/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
296                         HttpListenerContext ctx = _listener.GetContext ();
297                         Send (ctx.Response.OutputStream, "%%%OK%%%");
298                         ctx.Response.Close ();
299                         string response = Receive (ns, 512);
300                         ns.Close ();
301                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 200"));
302                         Assert.IsTrue (-1 == response.IndexOf ("Transfer-Encoding: chunked"));
303                 }
304
305                 [Test]
306 #if FEATURE_NO_BSD_SOCKETS
307                 [ExpectedException (typeof (PlatformNotSupportedException))]
308 #endif
309                 public void Test9 ()
310                 {
311                         var port = NetworkHelpers.FindFreePort ();
312                         // 1.0 + "Transfer-Encoding: chunked"
313                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test9/");
314                         NetworkStream ns = CreateNS (port);
315                         Send (ns, "POST /test9/ HTTP/1.0\r\nHost: 127.0.0.1\r\nTransfer-Encoding: chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n");
316                         bool timeout;
317                         string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
318                         ns.Close ();
319                         Assert.IsFalse (timeout);
320                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 411"));
321                 }
322
323                 [Test]
324 #if FEATURE_NO_BSD_SOCKETS
325                 [ExpectedException (typeof (PlatformNotSupportedException))]
326 #endif
327                 public void Test10 ()
328                 {
329                         var port = NetworkHelpers.FindFreePort ();
330                         // Same as Test9, but now we shutdown the socket for sending.
331                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test10/");
332                         MyNetworkStream ns = CreateNS (port);
333                         Send (ns, "POST /test10/ HTTP/1.0\r\nHost: 127.0.0.1\r\nTransfer-Encoding: chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n");
334                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
335                         bool timeout;
336                         string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
337                         ns.Close ();
338                         Assert.IsFalse (timeout);
339                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 411"));
340                 }
341
342                 [Test]
343 #if FEATURE_NO_BSD_SOCKETS
344                 [ExpectedException (typeof (PlatformNotSupportedException))]
345 #endif
346                 public void Test11 ()
347                 {
348                         var port = NetworkHelpers.FindFreePort ();
349                         // 0.9
350                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test11/");
351                         MyNetworkStream ns = CreateNS (port);
352                         Send (ns, "POST /test11/ HTTP/0.9\r\nHost: 127.0.0.1\r\n\r\n123");
353                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
354                         string input = Receive (ns, 512);
355                         ns.Close ();
356                         Assert.IsTrue(input.StartsWith ("HTTP/1.1 400"));
357                 }
358
359                 [Test]
360 #if FEATURE_NO_BSD_SOCKETS
361                 [ExpectedException (typeof (PlatformNotSupportedException))]
362 #endif
363                 public void Test12 ()
364                 {
365                         var port = NetworkHelpers.FindFreePort ();
366                         // 0.9
367                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test12/");
368                         MyNetworkStream ns = CreateNS (port);
369                         Send (ns, "POST /test12/ HTTP/0.9\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
370                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
371                         string input = Receive (ns, 512);
372                         ns.Close ();
373                         Assert.IsTrue(input.StartsWith ("HTTP/1.1 400"));
374                 }
375
376                 [Test]
377 #if FEATURE_NO_BSD_SOCKETS
378                 [ExpectedException (typeof (PlatformNotSupportedException))]
379 #endif
380                 public void Test13 ()
381                 {
382                         var port = NetworkHelpers.FindFreePort ();
383                         // 0.9
384                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test13/");
385                         MyNetworkStream ns = CreateNS (port);
386                         Send (ns, "GEt /test13/ HTTP/0.9\r\nHost: 127.0.0.1\r\n\r\n");
387                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
388                         string input = Receive (ns, 512);
389                         ns.Close ();
390                         Assert.IsTrue(input.StartsWith ("HTTP/1.1 400"));
391                 }
392
393                 HttpListenerRequest test14_request;
394                 ManualResetEvent test_evt;
395                 bool test14_error;
396                 [Test]
397 #if FEATURE_NO_BSD_SOCKETS
398                 [ExpectedException (typeof (PlatformNotSupportedException))]
399 #endif
400                 public void Test14 ()
401                 {
402                         var port = NetworkHelpers.FindFreePort ();
403                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test14/");
404                         MyNetworkStream ns = CreateNS (port);
405                         Send (ns, "POST /test14/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
406                         HttpListenerContext c = _listener.GetContext ();
407                         test14_request = c.Request;
408                         test_evt = new ManualResetEvent (false);
409                         Thread thread = new Thread (ReadToEnd);
410                         thread.Start ();
411                         if (test_evt.WaitOne (3000, false) == false) {
412 #if MONO_FEATURE_THREAD_ABORT
413                                 thread.Abort ();
414 #else
415                                 thread.Interrupt ();
416 #endif
417                                 test_evt.Close ();
418                                 Assert.IsTrue (false, "Timed out");
419                         }
420                         test_evt.Close ();
421                         c.Response.Close ();
422                         ns.Close ();
423                         Assert.AreEqual ("123", read_to_end, "Did not get the expected input.");
424                 }
425
426                 string read_to_end;
427                 void ReadToEnd ()
428                 {
429                         using (StreamReader r = new StreamReader (test14_request.InputStream)) {
430                                 read_to_end = r.ReadToEnd ();
431                                 test_evt.Set ();
432                         }
433                 }
434
435                 [Test]
436 #if FEATURE_NO_BSD_SOCKETS
437                 [ExpectedException (typeof (PlatformNotSupportedException))]
438 #endif
439                 public void Test15 ()
440                 {
441                         var port = NetworkHelpers.FindFreePort ();
442                         // 2 separate writes -> 2 packets. Body size > 8kB
443                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test15/");
444                         MyNetworkStream ns = CreateNS (port);
445                         Send (ns, "POST /test15/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 8888\r\n\r\n");
446                         Thread.Sleep (800);
447                         string data = new string ('a', 8888);
448                         Send (ns, data);
449                         HttpListenerContext c = _listener.GetContext ();
450                         HttpListenerRequest req = c.Request;
451                         using (StreamReader r = new StreamReader (req.InputStream)) {
452                                 read_to_end = r.ReadToEnd ();
453                         }
454                         Assert.AreEqual (read_to_end.Length, data.Length, "Wrong length");
455                         Assert.IsTrue (data == read_to_end, "Wrong data");
456                         c.Response.Close ();
457                         ns.Close ();
458                 }
459
460                 [Test]
461 #if FEATURE_NO_BSD_SOCKETS
462                 [ExpectedException (typeof (PlatformNotSupportedException))]
463 #endif
464                 public void Test16 ()
465                 {
466                         var port = NetworkHelpers.FindFreePort ();
467                         // 1 single write with headers + body (size > 8kB)
468                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test16/");
469                         MyNetworkStream ns = CreateNS (port);
470                         StringBuilder sb = new StringBuilder ();
471                         sb.Append ("POST /test16/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 8888\r\n\r\n");
472                         string eights = new string ('b', 8888);
473                         sb.Append (eights);
474                         string data = sb.ToString ();
475                         Send (ns, data);
476                         HttpListenerContext c = _listener.GetContext ();
477                         HttpListenerRequest req = c.Request;
478                         using (StreamReader r = new StreamReader (req.InputStream)) {
479                                 read_to_end = r.ReadToEnd ();
480                         }
481                         Assert.AreEqual (read_to_end.Length, read_to_end.Length, "Wrong length");
482                         Assert.IsTrue (eights == read_to_end, "Wrong data");
483                         c.Response.Close ();
484                         ns.Close ();
485                 }
486
487                 [Test]
488 #if FEATURE_NO_BSD_SOCKETS
489                 [ExpectedException (typeof (PlatformNotSupportedException))]
490 #endif
491                 public void Test17 ()
492                 {
493                         var port = NetworkHelpers.FindFreePort ();
494                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/test17/");
495                         NetworkStream ns = CreateNS (port);
496                         Send (ns, "RANDOM /test17/ HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
497                         HttpListenerContext ctx = _listener.GetContext ();
498                         Send (ctx.Response.OutputStream, "%%%OK%%%");
499                         ctx.Response.Close ();
500                         string response = Receive (ns, 1024);
501                         ns.Close ();
502                         Assert.IsTrue(response.StartsWith ("HTTP/1.1 200"));
503                         Assert.IsTrue(response.Contains ("Transfer-Encoding: chunked"));
504                 }
505
506                 [Test]
507 #if FEATURE_NO_BSD_SOCKETS
508                 [ExpectedException (typeof (PlatformNotSupportedException))]
509 #endif
510                 public void Test_MultipleClosesOnOuputStreamAllowed ()
511                 {
512                         var port = NetworkHelpers.FindFreePort ();
513                         _listener = CreateAndStartListener ("http://127.0.0.1:" + port + "/MultipleCloses/");
514                         NetworkStream ns = CreateNS (port);
515                         Send (ns, "GET /MultipleCloses/ HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n");
516
517                         HttpListenerContext ctx = _listener.GetContext ();
518                         ctx.Response.OutputStream.Close ();
519                         ctx.Response.OutputStream.Close ();
520                         ctx.Response.OutputStream.Close ();
521                         ctx.Response.Close ();
522                 }
523         
524                 void SendCookie ()
525                 {               
526                         NetworkStream ns = CreateNS (sendCookiePort);
527                         Send (ns, "GET /SendCookie/ HTTP/1.1\r\nHost: 127.0.0.1\r\n"+
528                                 "Cookie:$Version=\"1\"; "+
529                                 "Cookie1=Value1; $Path=\"/\"; "+
530                                 "CookieM=ValueM; $Path=\"/p2\"; $Domain=\"test\"; $Port=\"99\";"+
531                                 "Cookie2=Value2; $Path=\"/foo\";"+
532                                 "\r\n"+
533                                 "\r\n");
534                         ns.Flush ();
535                         Thread.Sleep (200);
536                         ns.Close();
537                 }
538
539                 [Test]
540 #if FEATURE_NO_BSD_SOCKETS
541                 [ExpectedException (typeof (PlatformNotSupportedException))]
542 #endif
543                 public void ReceiveCookiesFromClient ()
544                 {
545                         sendCookiePort = NetworkHelpers.FindFreePort ();                        
546                         _listener = CreateAndStartListener ("http://127.0.0.1:" + sendCookiePort + "/SendCookie/");
547                         Thread clientThread = new Thread (new ThreadStart (SendCookie));
548                         clientThread.Start ();
549
550                         HttpListenerContext context = _listener.GetContext();
551                         HttpListenerRequest request = context.Request;
552
553                         Assert.AreEqual (3, request.Cookies.Count, "#1");
554                         foreach (Cookie c in request.Cookies) {
555                                 if (c.Name == "Cookie1") {
556                                         Assert.AreEqual ("Value1", c.Value, "#2");
557                                         Assert.AreEqual ("\"/\"", c.Path, "#3");
558                                         Assert.AreEqual (0, c.Port.Length, "#4");
559                                         Assert.AreEqual (0, c.Domain.Length, "#5");
560                                 } else if (c.Name == "CookieM") {
561                                         Assert.AreEqual ("ValueM", c.Value, "#6");
562                                         Assert.AreEqual ("\"/p2\"", c.Path, "#7");
563                                         Assert.AreEqual ("\"99\"", c.Port, "#8");
564                                         Assert.AreEqual ("\"test\"", c.Domain, "#9");
565                                 } else if (c.Name == "Cookie2") {
566                                         Assert.AreEqual ("Value2", c.Value, "#10");
567                                         Assert.AreEqual ("\"/foo\"", c.Path, "#11");
568                                         Assert.AreEqual (0, c.Port.Length, "#12");
569                                         Assert.AreEqual (0, c.Domain.Length, "#13");
570                                 } else
571                                         Assert.Fail ("Invalid cookie name " + c.Name);
572                         }
573                 }
574
575                 private object _lock = new Object();
576                 private string cookieResponse;
577                 private int receiveCookiePort;
578                 private int sendCookiePort;             
579
580                 void ReceiveCookie () {
581                         lock (_lock) {
582                                 NetworkStream ns = CreateNS (receiveCookiePort);
583                                 Send (ns, "GET /ReceiveCookie/ HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n");
584                                 cookieResponse = Receive (ns, 512);
585                         }
586                 }
587
588                 [Test]
589 #if FEATURE_NO_BSD_SOCKETS
590                 [ExpectedException (typeof (PlatformNotSupportedException))]
591 #endif
592                 public void SendCookiestoClient ()
593                 {
594                         receiveCookiePort = NetworkHelpers.FindFreePort ();
595                         _listener = CreateAndStartListener ("http://127.0.0.1:" + receiveCookiePort + "/ReceiveCookie/");
596                         Thread clientThread = new Thread (new ThreadStart (ReceiveCookie));
597                         clientThread.Start ();
598
599                         HttpListenerContext context = _listener.GetContext();
600                         HttpListenerRequest request = context.Request;
601                         HttpListenerResponse response = context.Response;
602
603                         Cookie cookie = new Cookie ();
604                         cookie.Name = "Name0";
605                         cookie.Value = "Value0";
606                         cookie.Domain = "blue";
607                         cookie.Path = "/path/";
608                         cookie.Port = "\"80\"";
609                         cookie.Version = 1;
610                         response.Cookies.Add (cookie);
611
612                         string responseString = "<HTML><BODY>----</BODY></HTML>";
613                         byte[] buffer = Encoding.UTF8.GetBytes(responseString);
614                         response.ContentLength64 = buffer.Length;
615                         Stream output = response.OutputStream;
616                         output.Write(buffer, 0, buffer.Length);
617                         output.Flush ();
618                         response.Close();
619                         
620                         lock (_lock) {
621                                 bool foundCookie = false;
622                                 foreach (String str in cookieResponse.Split ('\n')) {
623                                         if (!str.StartsWith ("Set-Cookie"))
624                                                 continue;
625                                         Dictionary<string, String> dic = new Dictionary<string, String>();
626                                         foreach (String p in str.Substring (str.IndexOf (":") + 1).Split (';')) {
627                                                 String[] parts = p.Split('=');
628                                                 dic.Add (parts [0].Trim (), parts [1].Trim ());
629                                         }
630                                         Assert.AreEqual ("Value0", dic ["Name0"], "#1");
631                                         Assert.AreEqual ("blue", dic ["Domain"], "#2");
632                                         Assert.AreEqual ("\"/path/\"", dic ["Path"], "#3");
633                                         Assert.AreEqual ("\"80\"", dic ["Port"], "#4");
634                                         Assert.AreEqual ("1", dic ["Version"], "#5");
635                                         foundCookie = true;
636                                         break;
637                                 }
638                                 Assert.IsTrue (foundCookie, "#6");
639                         }
640                 }
641
642                 [Test]
643 #if FEATURE_NO_BSD_SOCKETS
644                 [ExpectedException (typeof (PlatformNotSupportedException))]
645 #endif
646                 public void MultiResponses ()
647                 {
648                         echoServerPort = NetworkHelpers.FindFreePort ();
649                         Thread srv = new Thread (new ThreadStart (EchoServer));
650                         srv.Start ();
651                         Thread.Sleep (200);
652
653                         for (int i = 0; i < 10; i++) {
654                                 string payload = string.Format (CultureInfo.InvariantCulture,
655                                         "Client{0}", i);
656
657                                 HttpWebRequest req = (HttpWebRequest) WebRequest.Create (
658                                         "http://localhost:" + echoServerPort + "/foobar/");
659                                 req.ServicePoint.Expect100Continue = false;
660                                 req.ServicePoint.UseNagleAlgorithm = false;
661                                 req.Method = "POST";
662                                 StreamWriter w = new StreamWriter (req.GetRequestStream ());
663                                 w.WriteLine (payload);
664                                 w.Close ();
665
666                                 HttpWebResponse resp = (HttpWebResponse) req.GetResponse ();
667                                 StreamReader r = new StreamReader (resp.GetResponseStream ());
668                                 Assert.AreEqual ("Hello, " + payload + "!", r.ReadToEnd ().Trim ());
669                                 r.Close ();
670                         }
671
672                         manualReset.Set ();
673                         srv.Join ();
674                 }
675
676                 int echoServerPort;
677                 void EchoServer ()
678                 {
679                         _listener = new HttpListener ();
680                         _listener.Prefixes.Add ("http://*:" + echoServerPort + "/foobar/");
681                         _listener.Start ();
682
683                         manualReset = new ManualResetEvent (false);
684
685                         IAsyncResult result = _listener.BeginGetContext (
686                                 new AsyncCallback (EchoCallback), _listener);
687                         manualReset.WaitOne ();
688                 }
689
690                 void EchoCallback (IAsyncResult result)
691                 {
692                         HttpListener listener = (HttpListener) result.AsyncState;
693                         HttpListenerContext context = listener.EndGetContext (result);
694                         HttpListenerRequest req = context.Request;
695                         StreamReader r = new StreamReader (req.InputStream);
696                         string reqBody = r.ReadToEnd ().Trim ();
697
698                         HttpListenerResponse resp = context.Response;
699                         StreamWriter o = new StreamWriter (resp.OutputStream);
700                         o.WriteLine ("Hello, " + reqBody + "!");
701                         o.Close ();
702
703                         listener.BeginGetContext (new AsyncCallback (EchoCallback), listener);
704                 }
705
706                 private ManualResetEvent manualReset;
707
708         }
709
710         [TestFixture]
711         public class HttpListenerBugs {
712                 [Test]
713 #if FEATURE_NO_BSD_SOCKETS
714                 [ExpectedException (typeof (PlatformNotSupportedException))]
715 #endif
716                 public void TestNonChunkedAsync ()
717                 {
718                         var port = NetworkHelpers.FindFreePort ();
719                         HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:" + port + "/");
720
721                         listener.BeginGetContext (callback, listener);
722                         
723                         HttpListener2Test.MyNetworkStream ns = HttpListener2Test.CreateNS (port);
724                         string message = "<script>\n"+
725                                 " <!-- register the blueprint for our show-headers service -->\n"+
726                                 " <action verb=\"POST\" path=\"/host/register\">\n" +
727                                 "    <blueprint>\n" +
728                                 "      <assembly>dream.tutorial.show-headers</assembly>\n" +
729                                 "      <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
730                                 "    </blueprint>\n" +
731                                 "  </action>\n" +
732                                 "\n" +
733                                 "  <!-- instantiate it -->\n" +
734                                 "  <action verb=\"POST\" path=\"/host/start\">\n" +
735                                 "    <config>\n" +
736                                 "      <path>show-headers</path>\n" +
737                                 "      <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
738                                 "    </config>\n" +
739                                 "  </action>\n" +
740                                 "</script>";
741                         string s = String.Format ("POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: {0}\r\n\r\n{1}",
742                                                 message.Length, message);  
743                         HttpListener2Test.Send (ns, s);
744                         bool timedout;
745                         string response = HttpListener2Test.ReceiveWithTimeout (ns, 1024, 3000, out timedout);
746                         ns.Close ();
747                         listener.Close ();
748                         Assert.IsFalse (timedout);
749                 }
750
751                 void callback (IAsyncResult ar)
752                 {
753                         HttpListener l = (HttpListener) ar.AsyncState;
754
755                         HttpListenerContext c = l.EndGetContext (ar);
756                         HttpListenerRequest request = c.Request;
757
758                         StreamReader r = new StreamReader (request.InputStream);
759                         string sr =r.ReadToEnd ();
760                         HttpListener2Test.Send (c.Response.OutputStream, "Miguel is love");
761                         c.Response.Close ();
762                 }
763
764                 //
765                 // As it turns out, when we closed the OutputStream,
766                 // we were not shutting down the connection, which was
767                 // a documented pattern to close the connection
768                 // 
769                 [Test]
770 #if FEATURE_NO_BSD_SOCKETS
771                 [ExpectedException (typeof (PlatformNotSupportedException))]
772 #endif
773                 public void Test_MultipleConnections ()
774                 {
775                         var port = NetworkHelpers.FindFreePort ();                      
776                         HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:" + port + "/multiple/");
777
778                         // First one
779                         NetworkStream ns = HttpListener2Test.CreateNS (port);
780                         HttpListener2Test.Send (ns, "POST /multiple/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
781                         HttpListenerContext ctx = listener.GetContext ();
782                         HttpListener2Test.Send (ctx.Response.OutputStream, "%%%OK%%%");
783                         ctx.Response.OutputStream.Close ();
784                         string response = HttpListener2Test.Receive (ns, 1024);
785                         ns.Close ();
786
787                         // Second one
788                         ns = HttpListener2Test.CreateNS (port);
789                         HttpListener2Test.Send (ns, "POST /multiple/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
790                         ctx = listener.GetContext ();
791                         HttpListener2Test.Send (ctx.Response.OutputStream, "%%%OK%%%");
792                         ctx.Response.OutputStream.Close ();
793                         response = HttpListener2Test.Receive (ns, 1024);
794                         ns.Close ();
795                         
796                         listener.Close ();
797                 }
798
799                 //
800                 // Test case for bug 341443, an pretty old bug, filed on November of 2007.
801                 //
802                 [Test]
803 #if FEATURE_NO_BSD_SOCKETS
804                 [ExpectedException (typeof (PlatformNotSupportedException))]
805 #endif
806                 public void Test_HostInUri ()
807                 {
808                         var wait = new ManualResetEvent (false);
809                         var wait2 = new ManualResetEvent (false);
810                         var port = NetworkHelpers.FindFreePort ();
811                         
812                         Thread t = new Thread (delegate (object a) {
813                                 wait.WaitOne ();
814
815                                 NetworkStream ns = HttpListener2Test.CreateNS (port);
816                                 HttpListener2Test.Send (ns, "GET http://www.google.com/ HTTP/1.1\r\nHost: www.google.com\r\nContent-Length: 3\r\n\r\n123456");
817
818                                 wait2.WaitOne ();
819                                 ns.Close ();
820                         });
821                         t.Start ();
822                                 
823                         HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://*:" + port + "/");
824                         wait.Set ();
825                         HttpListenerContext ctx = listener.GetContext ();
826                         
827                         Assert.AreEqual ("http://www.google.com:" + port + "/", ctx.Request.Url.ToString ());
828                         Assert.AreEqual ("http://www.google.com/", ctx.Request.RawUrl);
829                         wait2.Set ();
830
831                         listener.Close ();
832                 }
833
834                 [Test] // bug #513849
835 #if FEATURE_NO_BSD_SOCKETS
836                 [ExpectedException (typeof (PlatformNotSupportedException))]
837 #endif
838                 public void ClosePort ()
839                 {
840                         var port = NetworkHelpers.FindFreePort ();
841                         var h = new HttpListener ();
842                         h.Prefixes.Add ("http://127.0.0.1:" + port + "/");
843                         h.Start ();
844                         h.BeginGetContext (null, null);
845                         h.Stop ();
846                         TcpListener t = new TcpListener (IPAddress.Parse ("127.0.0.1"), port);
847                         t.Start ();
848                         t.Stop ();
849                 }
850
851                 //
852                 // Bugs: #17204, #10818
853                 //
854                 // Sadly, on Unix, if there are different calls to bind
855                 // like *:port and host:port that is not an error,
856                 // it would only be an error if host:port is done twice, so
857                 // the best we can hope for is that listening on a specific interface
858                 // does not also listen to another interface.
859                 //
860                 [Test]
861 #if FEATURE_NO_BSD_SOCKETS
862                 [ExpectedException (typeof (PlatformNotSupportedException))]
863 #endif
864                 public void BindToSingleInterface ()
865                 {
866                         IPAddress [] machineAddress = null;
867
868                         try {
869                                 machineAddress = Dns.GetHostAddresses (Dns.GetHostName ());
870                         } catch (SocketException){
871                                 // The build hosts sometimes can not resolve the hostname
872                                 Assert.Ignore ("Hostname couldn't be resolved.");
873                         }
874                         
875                         int port = NetworkHelpers.FindFreePort ();;
876                         var h = new HttpListener ();
877                         h.Prefixes.Add ("http://" + machineAddress [0] + ":" + port + "/");
878                         h.Start ();
879
880                         try {
881                                 var c = new TcpClient ("localhost", port);
882                                 Assert.Fail ("The TcpClient should have failed to connect since HttpListener is not listening on localhost");
883                         } catch (SocketException){
884                                 // Pass
885                         }
886                         h.Stop ();
887                 }
888
889                 [Test]
890 #if FEATURE_NO_BSD_SOCKETS
891                 [ExpectedException (typeof (PlatformNotSupportedException))]
892 #endif
893                 public void BindToAllInterfaces ()
894                 {
895                         var h = new HttpListener ();
896                         int port = NetworkHelpers.FindFreePort ();
897                         h.Prefixes.Add ("http://*:" + port + "/");
898                         h.Start ();
899                         var c = new TcpClient ("localhost", port);
900                         h.Stop ();
901                 }
902
903                 // Test case for bug #31209
904                 [Test]
905 #if FEATURE_NO_BSD_SOCKETS
906                 [ExpectedException (typeof (PlatformNotSupportedException))]
907 #endif
908                 public void Test_EmptyLineAtStart ()
909                 {
910                         var port = NetworkHelpers.FindFreePort ();
911                         var listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:" + port + "/");
912                         var ns = HttpListener2Test.CreateNS (port);
913
914                         HttpListener2Test.Send (ns, "\r\nGET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n");
915
916                         bool timedout;
917                         HttpListener2Test.GetContextWithTimeout (listener, 1000, out timedout);
918
919                         Assert.IsFalse (timedout, "timed out");
920
921                         ns.Close ();
922                         listener.Close ();
923                 }
924         }
925 }