2 // HttpListener2Test.cs
3 // - Unit tests for System.Net.HttpListener - connection testing
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
33 using System.Net.Sockets;
35 using System.Threading;
36 using NUnit.Framework;
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 {
45 [Ignore ("The class HttpListener is not supported")]
47 public class HttpListener2Test {
48 public class MyNetworkStream : NetworkStream {
49 public MyNetworkStream (Socket sock) : base (sock, true)
53 public Socket GetSocket ()
59 public static HttpListener CreateAndStartListener (string prefix)
61 HttpListener listener = new HttpListener ();
62 listener.Prefixes.Add (prefix);
67 public static MyNetworkStream CreateNS (int port)
69 Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
70 sock.Connect (new IPEndPoint (IPAddress.Loopback, port));
71 return new MyNetworkStream (sock);
74 public static void Send (Stream stream, string str)
76 byte [] bytes = Encoding.ASCII.GetBytes (str);
77 stream.Write (bytes, 0, bytes.Length);
80 public static string Receive (Stream stream, int size)
82 byte [] bytes = new byte [size];
83 int nread = stream.Read (bytes, 0, size);
84 return Encoding.ASCII.GetString (bytes, 0, nread);
87 public static string ReceiveWithTimeout (Stream stream, int size, int timeout, out bool timed_out)
89 byte [] bytes = new byte [size];
90 IAsyncResult ares = stream.BeginRead (bytes, 0, size, null, null);
91 timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
94 int nread = stream.EndRead (ares);
95 return Encoding.ASCII.GetString (bytes, 0, nread);
98 public static HttpListenerContext GetContextWithTimeout (HttpListener listener, int timeout, out bool timed_out)
100 IAsyncResult ares = listener.BeginGetContext (null, null);
101 timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
104 return listener.EndGetContext (ares);
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);
116 Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
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);
128 Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
134 StringBuilder bad = new StringBuilder ();
135 for (int i = 0; i < 33; i++){
137 bad.Append ((char) i);
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
162 string response = Receive (ns, 512);
165 Console.WriteLine ("Response is: {0}", response);
166 Assert.AreEqual (true, response.StartsWith ("HTTP/1.1 400"), String.Format ("Failed on {0}", (int) b));
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);
179 Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
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);
191 Assert.IsTrue (response.StartsWith ("HTTP/1.1 501"));
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);
204 Assert.IsTrue (response.StartsWith ("HTTP/1.1 501"));
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);
218 Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
219 Assert.IsTrue (-1 != response.IndexOf ("Transfer-Encoding: chunked"));
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);
234 Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
235 Assert.IsTrue (-1 == response.IndexOf ("Transfer-Encoding: chunked"));
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");
246 string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
247 Assert.IsFalse (timeout);
250 Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
254 public void Test10 ()
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);
262 string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
263 Assert.IsFalse (timeout);
266 Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
270 public void Test11 ()
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);
280 Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
284 public void Test12 ()
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);
294 Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
298 public void Test13 ()
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);
308 Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
311 HttpListenerRequest test14_request;
312 ManualResetEvent test_evt;
315 public void Test14 ()
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);
325 if (test_evt.WaitOne (3000, false) == false) {
328 Assert.IsTrue (false, "Timed out");
331 Assert.AreEqual ("123", read_to_end, "Did not get the expected input.");
339 using (StreamReader r = new StreamReader (test14_request.InputStream)) {
340 read_to_end = r.ReadToEnd ();
346 public void Test15 ()
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");
353 string data = new string ('a', 8888);
355 HttpListenerContext c = listener.GetContext ();
356 HttpListenerRequest req = c.Request;
357 using (StreamReader r = new StreamReader (req.InputStream)) {
358 read_to_end = r.ReadToEnd ();
360 Assert.AreEqual (read_to_end.Length, data.Length, "Wrong length");
361 Assert.IsTrue (data == read_to_end, "Wrong data");
367 public void Test16 ()
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);
376 string data = sb.ToString ();
378 HttpListenerContext c = listener.GetContext ();
379 HttpListenerRequest req = c.Request;
380 using (StreamReader r = new StreamReader (req.InputStream)) {
381 read_to_end = r.ReadToEnd ();
383 Assert.AreEqual (read_to_end.Length, read_to_end.Length, "Wrong length");
384 Assert.IsTrue (eights == read_to_end, "Wrong data");
390 public void Test17 ()
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);
400 Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
401 Assert.IsTrue (-1 != response.IndexOf ("Transfer-Encoding: chunked"));
406 public class HttpListenerBugs {
408 public void TestNonChunkedAsync ()
410 HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:9123/");
412 listener.BeginGetContext (callback, listener);
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" +
419 " <assembly>dream.tutorial.show-headers</assembly>\n" +
420 " <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
424 " <!-- instantiate it -->\n" +
425 " <action verb=\"POST\" path=\"/host/start\">\n" +
427 " <path>show-headers</path>\n" +
428 " <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
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);
436 string response = HttpListener2Test.ReceiveWithTimeout (ns, 1024, 3000, out timedout);
438 Assert.IsFalse (timedout);
441 void callback (IAsyncResult ar)
443 HttpListener l = (HttpListener) ar.AsyncState;
445 HttpListenerContext c = l.EndGetContext (ar);
446 HttpListenerRequest request = c.Request;
448 StreamReader r = new StreamReader (request.InputStream);
449 string sr =r.ReadToEnd ();
450 HttpListener2Test.Send (c.Response.OutputStream, "Miguel is love");