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