Excluded the tests, which are not working under Grasshopper (all changes under 'TARGE...
[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 #if NET_2_0
30 using System;
31 using System.IO;
32 using System.Net;
33 using System.Net.Sockets;
34 using System.Text;
35 using System.Threading;
36 using NUnit.Framework;
37
38 // ***************************************************************************************
39 // NOTE: when adding prefixes, make then unique per test, as MS might take 'some time' to
40 // unregister it even after explicitly closing the listener.
41 // ***************************************************************************************
42 namespace MonoTests.System.Net {
43         [TestFixture]
44 #if TARGET_JVM  
45         [Ignore ("The class HttpListener is not supported")]
46 #endif
47         public class HttpListener2Test {
48                 public class MyNetworkStream : NetworkStream {
49                         public MyNetworkStream (Socket sock) : base (sock, true)
50                         {
51                         }
52
53                         public Socket GetSocket ()
54                         {
55                                 return Socket;
56                         }
57                 }
58
59                 public static HttpListener CreateAndStartListener (string prefix)
60                 {
61                         HttpListener listener = new HttpListener ();
62                         listener.Prefixes.Add (prefix);
63                         listener.Start ();
64                         return listener;
65                 }
66
67                 public static MyNetworkStream CreateNS (int port)
68                 {
69                         Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
70                         sock.Connect (new IPEndPoint (IPAddress.Loopback, port));
71                         return new MyNetworkStream (sock);
72                 }
73
74                 public static void Send (Stream stream, string str)
75                 {
76                         byte [] bytes = Encoding.ASCII.GetBytes (str);
77                         stream.Write (bytes, 0, bytes.Length);
78                 }
79
80                 public static string Receive (Stream stream, int size)
81                 {
82                         byte [] bytes = new byte [size];
83                         int nread = stream.Read (bytes, 0, size);
84                         return Encoding.ASCII.GetString (bytes, 0, nread);
85                 }
86
87                 public static string ReceiveWithTimeout (Stream stream, int size, int timeout, out bool timed_out)
88                 {
89                         byte [] bytes = new byte [size];
90                         IAsyncResult ares = stream.BeginRead (bytes, 0, size, null, null);
91                         timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
92                         if (timed_out)
93                                 return null;
94                         int nread = stream.EndRead (ares);
95                         return Encoding.ASCII.GetString (bytes, 0, nread);
96                 }
97
98                 public static HttpListenerContext GetContextWithTimeout (HttpListener listener, int timeout, out bool timed_out)
99                 {
100                         IAsyncResult ares = listener.BeginGetContext (null, null);
101                         timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
102                         if (timed_out)
103                                 return null;
104                         return listener.EndGetContext (ares);
105                 }
106
107                 [Test]
108                 public void Test1 ()
109                 {
110                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test1/");
111                         NetworkStream ns = CreateNS (9000);
112                         Send (ns, "GET / HTTP/1.1\r\n\r\n"); // No host
113                         string response = Receive (ns, 512);
114                         ns.Close ();
115                         listener.Close ();
116                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
117                 }
118
119                 [Test]
120                 public void Test2 ()
121                 {
122                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test2/");
123                         NetworkStream ns = CreateNS (9000);
124                         Send (ns, "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"); // no prefix
125                         string response = Receive (ns, 512);
126                         ns.Close ();
127                         listener.Close ();
128                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
129                 }
130
131                 [Test]
132                 public void Test3 ()
133                 {
134                         StringBuilder bad = new StringBuilder ();
135                         for (int i = 0; i < 33; i++){
136                                 if (i != 13)
137                                         bad.Append ((char) i);
138                         }
139                         bad.Append ('(');
140                         bad.Append (')');
141                         bad.Append ('[');
142                         bad.Append (']');
143                         bad.Append ('<');
144                         bad.Append ('>');
145                         bad.Append ('@');
146                         bad.Append (',');
147                         bad.Append (';');
148                         bad.Append (':');
149                         bad.Append ('\\');
150                         bad.Append ('"');
151                         bad.Append ('/');
152                         bad.Append ('?');
153                         bad.Append ('=');
154                         bad.Append ('{');
155                         bad.Append ('}');
156
157                         foreach (char b in bad.ToString ()){
158                                 HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test3/");
159                                 NetworkStream ns = CreateNS (9000);
160                                 Send (ns, String.Format ("MA{0} / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n", b)); // bad method
161                                 
162                                 string response = Receive (ns, 512);
163                                 ns.Close ();
164                                 listener.Close ();
165                                 Console.WriteLine ("Response is: {0}", response);
166                                 Assert.AreEqual (true, response.StartsWith ("HTTP/1.1 400"), String.Format ("Failed on {0}", (int) b));
167                         }
168                 }
169
170                 [Test]
171                 public void Test4 ()
172                 {
173                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test4/");
174                         NetworkStream ns = CreateNS (9000);
175                         Send (ns, "POST /test4/ HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"); // length required
176                         string response = Receive (ns, 512);
177                         ns.Close ();
178                         listener.Close ();
179                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
180                 }
181
182                 [Test]
183                 public void Test5 ()
184                 {
185                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test5/");
186                         NetworkStream ns = CreateNS (9000);
187                         Send (ns, "POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nTransfer-Encoding: pepe\r\n\r\n"); // not implemented
188                         string response = Receive (ns, 512);
189                         ns.Close ();
190                         listener.Close ();
191                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 501"));
192                 }
193
194                 [Test]
195                 public void Test6 ()
196                 {
197                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test6/");
198                         NetworkStream ns = CreateNS (9000);
199                          // not implemented! This is against the RFC. Should be a bad request/length required
200                         Send (ns, "POST /test6/ HTTP/1.1\r\nHost: 127.0.0.1\r\nTransfer-Encoding: identity\r\n\r\n");
201                         string response = Receive (ns, 512);
202                         ns.Close ();
203                         listener.Close ();
204                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 501"));
205                 }
206
207                 [Test]
208                 public void Test7 ()
209                 {
210                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test7/");
211                         NetworkStream ns = CreateNS (9000);
212                         Send (ns, "POST /test7/ HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
213                         HttpListenerContext ctx = listener.GetContext ();
214                         Send (ctx.Response.OutputStream, "%%%OK%%%");
215                         string response = Receive (ns, 1024);
216                         ns.Close ();
217                         listener.Close ();
218                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
219                         Assert.IsTrue (-1 != response.IndexOf ("Transfer-Encoding: chunked"));
220                 }
221
222                 [Test]
223                 public void Test8 ()
224                 {
225                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test8/");
226                         NetworkStream ns = CreateNS (9000);
227                         // Just like Test7, but 1.0
228                         Send (ns, "POST /test8/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
229                         HttpListenerContext ctx = listener.GetContext ();
230                         Send (ctx.Response.OutputStream, "%%%OK%%%");
231                         string response = Receive (ns, 512);
232                         ns.Close ();
233                         listener.Close ();
234                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
235                         Assert.IsTrue (-1 == response.IndexOf ("Transfer-Encoding: chunked"));
236                 }
237
238                 [Test]
239                 public void Test9 ()
240                 {
241                         // 1.0 + "Transfer-Encoding: chunked"
242                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test9/");
243                         NetworkStream ns = CreateNS (9000);
244                         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");
245                         bool timeout;
246                         string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
247                         Assert.IsFalse (timeout);
248                         listener.Close ();
249                         ns.Close ();
250                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
251                 }
252
253                 [Test]
254                 public void Test10 ()
255                 {
256                         // Same as Test9, but now we shutdown the socket for sending.
257                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test10/");
258                         MyNetworkStream ns = CreateNS (9000);
259                         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");
260                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
261                         bool timeout;
262                         string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
263                         Assert.IsFalse (timeout);
264                         listener.Close ();
265                         ns.Close ();
266                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
267                 }
268
269                 [Test]
270                 public void Test11 ()
271                 {
272                         // 0.9
273                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test11/");
274                         MyNetworkStream ns = CreateNS (9000);
275                         Send (ns, "POST /test11/ HTTP/0.9\r\nHost: 127.0.0.1\r\n\r\n123");
276                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
277                         string input = Receive (ns, 512);
278                         ns.Close ();
279                         listener.Close ();
280                         Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
281                 }
282
283                 [Test]
284                 public void Test12 ()
285                 {
286                         // 0.9
287                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test12/");
288                         MyNetworkStream ns = CreateNS (9000);
289                         Send (ns, "POST /test12/ HTTP/0.9\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
290                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
291                         string input = Receive (ns, 512);
292                         ns.Close ();
293                         listener.Close ();
294                         Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
295                 }
296
297                 [Test]
298                 public void Test13 ()
299                 {
300                         // 0.9
301                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test13/");
302                         MyNetworkStream ns = CreateNS (9000);
303                         Send (ns, "GEt /test13/ HTTP/0.9\r\nHost: 127.0.0.1\r\n\r\n");
304                         ns.GetSocket ().Shutdown (SocketShutdown.Send);
305                         string input = Receive (ns, 512);
306                         ns.Close ();
307                         listener.Close ();
308                         Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
309                 }
310
311                 HttpListenerRequest test14_request;
312                 ManualResetEvent test_evt;
313                 bool test14_error;
314                 [Test]
315                 public void Test14 ()
316                 {
317                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test14/");
318                         MyNetworkStream ns = CreateNS (9000);
319                         Send (ns, "POST /test14/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
320                         HttpListenerContext c = listener.GetContext ();
321                         test14_request = c.Request;
322                         test_evt = new ManualResetEvent (false);
323                         Thread thread = new Thread (ReadToEnd);
324                         thread.Start ();
325                         if (test_evt.WaitOne (3000, false) == false) {
326                                 thread.Abort ();
327                                 test_evt.Close ();
328                                 Assert.IsTrue (false, "Timed out");
329                         }
330                         test_evt.Close ();
331                         Assert.AreEqual ("123", read_to_end, "Did not get the expected input.");
332                         c.Response.Close ();
333                         ns.Close ();
334                 }
335
336                 string read_to_end;
337                 void ReadToEnd ()
338                 {
339                         using (StreamReader r = new StreamReader (test14_request.InputStream)) {
340                                 read_to_end = r.ReadToEnd ();
341                                 test_evt.Set ();
342                         }
343                 }
344
345                 [Test]
346                 public void Test15 ()
347                 {
348                         // 2 separate writes -> 2 packets. Body size > 8kB
349                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test15/");
350                         MyNetworkStream ns = CreateNS (9000);
351                         Send (ns, "POST /test15/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 8888\r\n\r\n");
352                         Thread.Sleep (800);
353                         string data = new string ('a', 8888);
354                         Send (ns, data);
355                         HttpListenerContext c = listener.GetContext ();
356                         HttpListenerRequest req = c.Request;
357                         using (StreamReader r = new StreamReader (req.InputStream)) {
358                                 read_to_end = r.ReadToEnd ();
359                         }
360                         Assert.AreEqual (read_to_end.Length, data.Length, "Wrong length");
361                         Assert.IsTrue (data == read_to_end, "Wrong data");
362                         c.Response.Close ();
363                         ns.Close ();
364                 }
365
366                 [Test]
367                 public void Test16 ()
368                 {
369                         // 1 single write with headers + body (size > 8kB)
370                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test16/");
371                         MyNetworkStream ns = CreateNS (9000);
372                         StringBuilder sb = new StringBuilder ();
373                         sb.Append ("POST /test16/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 8888\r\n\r\n");
374                         string eights = new string ('b', 8888);
375                         sb.Append (eights);
376                         string data = sb.ToString ();
377                         Send (ns, data);
378                         HttpListenerContext c = listener.GetContext ();
379                         HttpListenerRequest req = c.Request;
380                         using (StreamReader r = new StreamReader (req.InputStream)) {
381                                 read_to_end = r.ReadToEnd ();
382                         }
383                         Assert.AreEqual (read_to_end.Length, read_to_end.Length, "Wrong length");
384                         Assert.IsTrue (eights == read_to_end, "Wrong data");
385                         c.Response.Close ();
386                         ns.Close ();
387                 }
388
389                 [Test]
390                 public void Test17 ()
391                 {
392                         HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test17/");
393                         NetworkStream ns = CreateNS (9000);
394                         Send (ns, "RANDOM /test17/ HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
395                         HttpListenerContext ctx = listener.GetContext ();
396                         Send (ctx.Response.OutputStream, "%%%OK%%%");
397                         string response = Receive (ns, 1024);
398                         ns.Close ();
399                         listener.Close ();
400                         Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
401                         Assert.IsTrue (-1 != response.IndexOf ("Transfer-Encoding: chunked"));
402                 }
403         }
404
405         [TestFixture]
406         public class HttpListenerBugs {
407                 [Test]
408                 public void TestNonChunkedAsync ()
409                 {
410                         HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:9123/");
411
412                         listener.BeginGetContext (callback, listener);
413                         
414                         HttpListener2Test.MyNetworkStream ns = HttpListener2Test.CreateNS (9123);
415                         string message = "<script>\n"+
416                                 " <!-- register the blueprint for our show-headers service -->\n"+
417                                 " <action verb=\"POST\" path=\"/host/register\">\n" +
418                                 "    <blueprint>\n" +
419                                 "      <assembly>dream.tutorial.show-headers</assembly>\n" +
420                                 "      <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
421                                 "    </blueprint>\n" +
422                                 "  </action>\n" +
423                                 "\n" +
424                                 "  <!-- instantiate it -->\n" +
425                                 "  <action verb=\"POST\" path=\"/host/start\">\n" +
426                                 "    <config>\n" +
427                                 "      <path>show-headers</path>\n" +
428                                 "      <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
429                                 "    </config>\n" +
430                                 "  </action>\n" +
431                                 "</script>";
432                         string s = String.Format ("POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: {0}\r\n\r\n{1}",
433                                                 message.Length, message);  
434                         HttpListener2Test.Send (ns, s);
435                         bool timedout;
436                         string response = HttpListener2Test.ReceiveWithTimeout (ns, 1024, 3000, out timedout);
437                         ns.Close ();
438                         Assert.IsFalse (timedout);
439                 }
440
441                 void callback (IAsyncResult ar)
442                 {
443                         HttpListener l = (HttpListener) ar.AsyncState;
444
445                         HttpListenerContext c = l.EndGetContext (ar);
446                         HttpListenerRequest request = c.Request;
447
448                         StreamReader r = new StreamReader (request.InputStream);
449                         string sr =r.ReadToEnd ();
450                         HttpListener2Test.Send (c.Response.OutputStream, "Miguel is love");
451                 }
452         }
453 }
454 #endif
455