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