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