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