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