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 {
44 public class HttpListener2Test {
45 public class MyNetworkStream : NetworkStream {
46 public MyNetworkStream (Socket sock) : base (sock, true)
50 public Socket GetSocket ()
56 public static HttpListener CreateAndStartListener (string prefix)
58 HttpListener listener = new HttpListener ();
59 listener.Prefixes.Add (prefix);
64 public static MyNetworkStream CreateNS (int port)
66 Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
67 sock.Connect (new IPEndPoint (IPAddress.Loopback, port));
68 return new MyNetworkStream (sock);
71 public static void Send (Stream stream, string str)
73 byte [] bytes = Encoding.ASCII.GetBytes (str);
74 stream.Write (bytes, 0, bytes.Length);
77 public static string Receive (Stream stream, int size)
79 byte [] bytes = new byte [size];
80 int nread = stream.Read (bytes, 0, size);
81 return Encoding.ASCII.GetString (bytes, 0, nread);
84 public static string ReceiveWithTimeout (Stream stream, int size, int timeout, out bool timed_out)
86 byte [] bytes = new byte [size];
87 IAsyncResult ares = stream.BeginRead (bytes, 0, size, null, null);
88 timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
91 int nread = stream.EndRead (ares);
92 return Encoding.ASCII.GetString (bytes, 0, nread);
95 public static HttpListenerContext GetContextWithTimeout (HttpListener listener, int timeout, out bool timed_out)
97 IAsyncResult ares = listener.BeginGetContext (null, null);
98 timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
101 return listener.EndGetContext (ares);
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);
113 Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
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);
125 Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
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);
137 Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
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);
149 Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
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);
161 Assert.IsTrue (response.StartsWith ("HTTP/1.1 501"));
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);
174 Assert.IsTrue (response.StartsWith ("HTTP/1.1 501"));
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);
188 Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
189 Assert.IsTrue (-1 != response.IndexOf ("Transfer-Encoding: chunked"));
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);
204 Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
205 Assert.IsTrue (-1 == response.IndexOf ("Transfer-Encoding: chunked"));
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");
216 string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
217 Assert.IsFalse (timeout);
220 Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
224 public void Test10 ()
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);
232 string response = ReceiveWithTimeout (ns, 512, 1000, out timeout);
233 Assert.IsFalse (timeout);
236 Assert.IsTrue (response.StartsWith ("HTTP/1.1 411"));
240 public void Test11 ()
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);
250 Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
254 public void Test12 ()
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);
264 Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
268 public void Test13 ()
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);
278 Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
281 HttpListenerRequest test14_request;
282 ManualResetEvent test_evt;
285 public void Test14 ()
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);
295 if (test_evt.WaitOne (3000, false) == false) {
298 Assert.IsTrue (false, "Timed out");
301 Assert.AreEqual ("123", read_to_end, "Did not get the expected input.");
309 using (StreamReader r = new StreamReader (test14_request.InputStream)) {
310 read_to_end = r.ReadToEnd ();
316 public void Test15 ()
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");
323 string data = new string ('a', 8888);
325 HttpListenerContext c = listener.GetContext ();
326 HttpListenerRequest req = c.Request;
327 using (StreamReader r = new StreamReader (req.InputStream)) {
328 read_to_end = r.ReadToEnd ();
330 Assert.AreEqual (read_to_end.Length, data.Length, "Wrong length");
331 Assert.IsTrue (data == read_to_end, "Wrong data");
337 public void Test16 ()
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);
346 string data = sb.ToString ();
348 HttpListenerContext c = listener.GetContext ();
349 HttpListenerRequest req = c.Request;
350 using (StreamReader r = new StreamReader (req.InputStream)) {
351 read_to_end = r.ReadToEnd ();
353 Assert.AreEqual (read_to_end.Length, read_to_end.Length, "Wrong length");
354 Assert.IsTrue (eights == read_to_end, "Wrong data");
361 public class HttpListenerBugs {
363 public void TestNonChunkedAsync ()
365 HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:9123/");
367 listener.BeginGetContext (callback, listener);
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" +
374 " <assembly>dream.tutorial.show-headers</assembly>\n" +
375 " <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
379 " <!-- instantiate it -->\n" +
380 " <action verb=\"POST\" path=\"/host/start\">\n" +
382 " <path>show-headers</path>\n" +
383 " <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
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);
391 string response = HttpListener2Test.ReceiveWithTimeout (ns, 1024, 3000, out timedout);
393 Assert.IsFalse (timedout);
396 void callback (IAsyncResult ar)
398 HttpListener l = (HttpListener) ar.AsyncState;
400 HttpListenerContext c = l.EndGetContext (ar);
401 HttpListenerRequest request = c.Request;
403 StreamReader r = new StreamReader (request.InputStream);
404 string sr =r.ReadToEnd ();
405 HttpListener2Test.Send (c.Response.OutputStream, "Miguel is love");