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