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