//
#if NET_2_0
using System;
+using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
// ***************************************************************************************
namespace MonoTests.System.Net {
[TestFixture]
+#if TARGET_JVM
+ [Ignore ("The class HttpListener is not supported")]
+#endif
public class HttpListener2Test {
- class MyNetworkStream : NetworkStream {
+ public class MyNetworkStream : NetworkStream {
public MyNetworkStream (Socket sock) : base (sock, true)
{
}
}
}
- HttpListener CreateAndStartListener (string prefix)
+ public static HttpListener CreateAndStartListener (string prefix)
+ {
+ HttpListener listener = new HttpListener ();
+ listener.Prefixes.Add (prefix);
+ listener.Start ();
+ return listener;
+ }
+
+ public static HttpListener CreateAndStartListener (string prefix, AuthenticationSchemes authSchemes)
{
HttpListener listener = new HttpListener ();
+ listener.AuthenticationSchemes = authSchemes;
listener.Prefixes.Add (prefix);
listener.Start ();
return listener;
}
- MyNetworkStream CreateNS (int port)
+ public static MyNetworkStream CreateNS (int port)
{
Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect (new IPEndPoint (IPAddress.Loopback, port));
return new MyNetworkStream (sock);
}
- void Send (Stream stream, string str)
+ public static void Send (Stream stream, string str)
{
byte [] bytes = Encoding.ASCII.GetBytes (str);
stream.Write (bytes, 0, bytes.Length);
}
- string Receive (Stream stream, int size)
+ public static string Receive (Stream stream, int size)
{
byte [] bytes = new byte [size];
int nread = stream.Read (bytes, 0, size);
return Encoding.ASCII.GetString (bytes, 0, nread);
}
- string ReceiveWithTimeout (Stream stream, int size, int timeout, out bool timed_out)
+ public static string ReceiveWithTimeout (Stream stream, int size, int timeout, out bool timed_out)
{
byte [] bytes = new byte [size];
IAsyncResult ares = stream.BeginRead (bytes, 0, size, null, null);
return Encoding.ASCII.GetString (bytes, 0, nread);
}
- HttpListenerContext GetContextWithTimeout (HttpListener listener, int timeout, out bool timed_out)
+ public static HttpListenerContext GetContextWithTimeout (HttpListener listener, int timeout, out bool timed_out)
{
IAsyncResult ares = listener.BeginGetContext (null, null);
timed_out = !ares.AsyncWaitHandle.WaitOne (timeout, false);
[Test]
public void Test3 ()
{
- HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test3/");
- NetworkStream ns = CreateNS (9000);
- Send (ns, "MET / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n"); // bad method
- string response = Receive (ns, 512);
- ns.Close ();
- listener.Close ();
- Assert.IsTrue (response.StartsWith ("HTTP/1.1 400"));
+ StringBuilder bad = new StringBuilder ();
+ for (int i = 0; i < 33; i++){
+ if (i != 13)
+ bad.Append ((char) i);
+ }
+ bad.Append ('(');
+ bad.Append (')');
+ bad.Append ('[');
+ bad.Append (']');
+ bad.Append ('<');
+ bad.Append ('>');
+ bad.Append ('@');
+ bad.Append (',');
+ bad.Append (';');
+ bad.Append (':');
+ bad.Append ('\\');
+ bad.Append ('"');
+ bad.Append ('/');
+ bad.Append ('?');
+ bad.Append ('=');
+ bad.Append ('{');
+ bad.Append ('}');
+
+ foreach (char b in bad.ToString ()){
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test3/");
+ NetworkStream ns = CreateNS (9000);
+ Send (ns, String.Format ("MA{0} / HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n", b)); // bad method
+
+ string response = Receive (ns, 512);
+ ns.Close ();
+ listener.Close ();
+ Assert.AreEqual (true, response.StartsWith ("HTTP/1.1 400"), String.Format ("Failed on {0}", (int) b));
+ }
}
[Test]
Send (ns, "POST /test7/ HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
HttpListenerContext ctx = listener.GetContext ();
Send (ctx.Response.OutputStream, "%%%OK%%%");
- string response = Receive (ns, 512);
+ string response = Receive (ns, 1024);
ns.Close ();
listener.Close ();
Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
listener.Close ();
Assert.IsTrue (input.StartsWith ("HTTP/1.1 400"));
}
+
+ HttpListenerRequest test14_request;
+ ManualResetEvent test_evt;
+ bool test14_error;
+ [Test]
+ public void Test14 ()
+ {
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test14/");
+ MyNetworkStream ns = CreateNS (9000);
+ Send (ns, "POST /test14/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
+ HttpListenerContext c = listener.GetContext ();
+ test14_request = c.Request;
+ test_evt = new ManualResetEvent (false);
+ Thread thread = new Thread (ReadToEnd);
+ thread.Start ();
+ if (test_evt.WaitOne (3000, false) == false) {
+ thread.Abort ();
+ test_evt.Close ();
+ Assert.IsTrue (false, "Timed out");
+ }
+ test_evt.Close ();
+ Assert.AreEqual ("123", read_to_end, "Did not get the expected input.");
+ c.Response.Close ();
+ ns.Close ();
+ }
+
+ string read_to_end;
+ void ReadToEnd ()
+ {
+ using (StreamReader r = new StreamReader (test14_request.InputStream)) {
+ read_to_end = r.ReadToEnd ();
+ test_evt.Set ();
+ }
+ }
+
+ [Test]
+ public void Test15 ()
+ {
+ // 2 separate writes -> 2 packets. Body size > 8kB
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test15/");
+ MyNetworkStream ns = CreateNS (9000);
+ Send (ns, "POST /test15/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 8888\r\n\r\n");
+ Thread.Sleep (800);
+ string data = new string ('a', 8888);
+ Send (ns, data);
+ HttpListenerContext c = listener.GetContext ();
+ HttpListenerRequest req = c.Request;
+ using (StreamReader r = new StreamReader (req.InputStream)) {
+ read_to_end = r.ReadToEnd ();
+ }
+ Assert.AreEqual (read_to_end.Length, data.Length, "Wrong length");
+ Assert.IsTrue (data == read_to_end, "Wrong data");
+ c.Response.Close ();
+ ns.Close ();
+ }
+
+ [Test]
+ public void Test16 ()
+ {
+ // 1 single write with headers + body (size > 8kB)
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test16/");
+ MyNetworkStream ns = CreateNS (9000);
+ StringBuilder sb = new StringBuilder ();
+ sb.Append ("POST /test16/ HTTP/1.0\r\nHost: 127.0.0.1\r\nContent-Length: 8888\r\n\r\n");
+ string eights = new string ('b', 8888);
+ sb.Append (eights);
+ string data = sb.ToString ();
+ Send (ns, data);
+ HttpListenerContext c = listener.GetContext ();
+ HttpListenerRequest req = c.Request;
+ using (StreamReader r = new StreamReader (req.InputStream)) {
+ read_to_end = r.ReadToEnd ();
+ }
+ Assert.AreEqual (read_to_end.Length, read_to_end.Length, "Wrong length");
+ Assert.IsTrue (eights == read_to_end, "Wrong data");
+ c.Response.Close ();
+ ns.Close ();
+ }
+
+ [Test]
+ public void Test17 ()
+ {
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/test17/");
+ NetworkStream ns = CreateNS (9000);
+ Send (ns, "RANDOM /test17/ HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: 3\r\n\r\n123");
+ HttpListenerContext ctx = listener.GetContext ();
+ Send (ctx.Response.OutputStream, "%%%OK%%%");
+ string response = Receive (ns, 1024);
+ ns.Close ();
+ listener.Close ();
+ Assert.IsTrue (response.StartsWith ("HTTP/1.1 200"));
+ Assert.IsTrue (-1 != response.IndexOf ("Transfer-Encoding: chunked"));
+ }
+
+ [Test]
+ public void Test_MultipleClosesOnOuputStreamAllowed ()
+ {
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/MultipleCloses/");
+ NetworkStream ns = CreateNS (9000);
+ Send (ns, "GET /MultipleCloses/ HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n");
+
+ HttpListenerContext ctx = listener.GetContext ();
+ ctx.Response.OutputStream.Close ();
+ ctx.Response.OutputStream.Close ();
+ ctx.Response.OutputStream.Close ();
+ ctx.Response.Close ();
+ listener.Close ();
+ }
+
+ void SendCookie ()
+ {
+ NetworkStream ns = CreateNS (9000);
+ Send (ns, "GET /SendCookie/ HTTP/1.1\r\nHost: 127.0.0.1\r\n"+
+ "Cookie:$Version=\"1\"; "+
+ "Cookie1=Value1; $Path=\"/\"; "+
+ "CookieM=ValueM; $Path=\"/p2\"; $Domain=\"test\"; $Port=\"99\";"+
+ "Cookie2=Value2; $Path=\"/foo\";"+
+ "\r\n"+
+ "\r\n");
+ ns.Flush ();
+ Thread.Sleep (200);
+ ns.Close();
+ }
+
+ [Test]
+ public void ReceiveCookiesFromClient ()
+ {
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/SendCookie/");
+ Thread clientThread = new Thread (new ThreadStart (SendCookie));
+ clientThread.Start ();
+
+ HttpListenerContext context = listener.GetContext();
+ HttpListenerRequest request = context.Request;
+
+ Assert.AreEqual (3, request.Cookies.Count, "#1");
+ foreach (Cookie c in request.Cookies) {
+ if (c.Name == "Cookie1") {
+ Assert.AreEqual ("Value1", c.Value, "#2");
+ Assert.AreEqual ("\"/\"", c.Path, "#3");
+ Assert.AreEqual (0, c.Port.Length, "#4");
+ Assert.AreEqual (0, c.Domain.Length, "#5");
+ } else if (c.Name == "CookieM") {
+ Assert.AreEqual ("ValueM", c.Value, "#6");
+ Assert.AreEqual ("\"/p2\"", c.Path, "#7");
+ Assert.AreEqual ("\"99\"", c.Port, "#8");
+ Assert.AreEqual ("\"test\"", c.Domain, "#9");
+ } else if (c.Name == "Cookie2") {
+ Assert.AreEqual ("Value2", c.Value, "#10");
+ Assert.AreEqual ("\"/foo\"", c.Path, "#11");
+ Assert.AreEqual (0, c.Port.Length, "#12");
+ Assert.AreEqual (0, c.Domain.Length, "#13");
+ } else
+ Assert.Fail ("Invalid cookie name " + c.Name);
+ }
+
+ listener.Close ();
+ }
+
+ private object _lock = new Object();
+ private string cookieResponse;
+
+ void ReceiveCookie () {
+ lock (_lock) {
+ NetworkStream ns = CreateNS (9000);
+ Send (ns, "GET /ReceiveCookie/ HTTP/1.1\r\nHost: 127.0.0.1\r\n\r\n");
+ cookieResponse = Receive (ns, 512);
+ }
+ }
+
+ [Test]
+ public void SendCookiestoClient ()
+ {
+ HttpListener listener = CreateAndStartListener ("http://127.0.0.1:9000/ReceiveCookie/");
+ Thread clientThread = new Thread (new ThreadStart (ReceiveCookie));
+ clientThread.Start ();
+
+ HttpListenerContext context = listener.GetContext();
+ HttpListenerRequest request = context.Request;
+ HttpListenerResponse response = context.Response;
+
+ Cookie cookie = new Cookie ();
+ cookie.Name = "Name0";
+ cookie.Value = "Value0";
+ cookie.Domain = "blue";
+ cookie.Path = "/path/";
+ cookie.Port = "\"80\"";
+ cookie.Version = 1;
+ response.Cookies.Add (cookie);
+
+ string responseString = "<HTML><BODY>----</BODY></HTML>";
+ byte[] buffer = Encoding.UTF8.GetBytes(responseString);
+ response.ContentLength64 = buffer.Length;
+ Stream output = response.OutputStream;
+ output.Write(buffer, 0, buffer.Length);
+ output.Flush ();
+ response.Close();
+
+ lock (_lock) {
+ bool foundCookie = false;
+ foreach (String str in cookieResponse.Split ('\n')) {
+ if (!str.StartsWith ("Set-Cookie2"))
+ continue;
+ Dictionary<string, String> dic = new Dictionary<string, String>();
+ foreach (String p in str.Substring (str.IndexOf (":") + 1).Split (';')) {
+ String[] parts = p.Split('=');
+ dic.Add (parts [0].Trim (), parts [1].Trim ());
+ }
+ Assert.AreEqual ("Value0", dic ["Name0"], "#1");
+ Assert.AreEqual ("blue", dic ["Domain"], "#2");
+ Assert.AreEqual ("\"/path/\"", dic ["Path"], "#3");
+ Assert.AreEqual ("\"80\"", dic ["Port"], "#4");
+ Assert.AreEqual ("1", dic ["Version"], "#5");
+ foundCookie = true;
+ break;
+ }
+ Assert.IsTrue (foundCookie, "#6");
+ }
+
+ listener.Close ();
+ }
+
+ [Test]
+ public void MultiResponses ()
+ {
+ Thread srv = new Thread (new ThreadStart (EchoServer));
+ srv.Start ();
+ Thread.Sleep (200);
+
+ for (int i = 0; i < 10; i++) {
+ string payload = string.Format (CultureInfo.InvariantCulture,
+ "Client{0}", i);
+
+ HttpWebRequest req = (HttpWebRequest) WebRequest.Create (
+ "http://localhost:8888/foobar/");
+ req.ServicePoint.Expect100Continue = false;
+ req.ServicePoint.UseNagleAlgorithm = false;
+ req.Method = "POST";
+ StreamWriter w = new StreamWriter (req.GetRequestStream ());
+ w.WriteLine (payload);
+ w.Close ();
+
+ HttpWebResponse resp = (HttpWebResponse) req.GetResponse ();
+ StreamReader r = new StreamReader (resp.GetResponseStream ());
+ Assert.AreEqual ("Hello, " + payload + "!", r.ReadToEnd ().Trim ());
+ r.Close ();
+ }
+
+ manualReset.Set ();
+ srv.Join ();
+ }
+
+ void EchoServer ()
+ {
+ HttpListener listener = new HttpListener ();
+ listener.Prefixes.Add ("http://*:8888/foobar/");
+ listener.Start ();
+
+ manualReset = new ManualResetEvent (false);
+
+ IAsyncResult result = listener.BeginGetContext (
+ new AsyncCallback (EchoCallback), listener);
+ manualReset.WaitOne ();
+ }
+
+ void EchoCallback (IAsyncResult result)
+ {
+ HttpListener listener = (HttpListener) result.AsyncState;
+ HttpListenerContext context = listener.EndGetContext (result);
+ HttpListenerRequest req = context.Request;
+ StreamReader r = new StreamReader (req.InputStream);
+ string reqBody = r.ReadToEnd ().Trim ();
+
+ HttpListenerResponse resp = context.Response;
+ StreamWriter o = new StreamWriter (resp.OutputStream);
+ o.WriteLine ("Hello, " + reqBody + "!");
+ o.Close ();
+
+ listener.BeginGetContext (new AsyncCallback (EchoCallback), listener);
+ }
+
+ private ManualResetEvent manualReset;
+
+ }
+
+ [TestFixture]
+ public class HttpListenerBugs {
+ [Test]
+ public void TestNonChunkedAsync ()
+ {
+ HttpListener listener = HttpListener2Test.CreateAndStartListener ("http://127.0.0.1:9123/");
+
+ listener.BeginGetContext (callback, listener);
+
+ HttpListener2Test.MyNetworkStream ns = HttpListener2Test.CreateNS (9123);
+ string message = "<script>\n"+
+ " <!-- register the blueprint for our show-headers service -->\n"+
+ " <action verb=\"POST\" path=\"/host/register\">\n" +
+ " <blueprint>\n" +
+ " <assembly>dream.tutorial.show-headers</assembly>\n" +
+ " <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
+ " </blueprint>\n" +
+ " </action>\n" +
+ "\n" +
+ " <!-- instantiate it -->\n" +
+ " <action verb=\"POST\" path=\"/host/start\">\n" +
+ " <config>\n" +
+ " <path>show-headers</path>\n" +
+ " <class>MindTouch.Dream.Tutorial.ShowHeadersService</class>\n" +
+ " </config>\n" +
+ " </action>\n" +
+ "</script>";
+ string s = String.Format ("POST / HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length: {0}\r\n\r\n{1}",
+ message.Length, message);
+ HttpListener2Test.Send (ns, s);
+ bool timedout;
+ string response = HttpListener2Test.ReceiveWithTimeout (ns, 1024, 3000, out timedout);
+ ns.Close ();
+ Assert.IsFalse (timedout);
+ }
+
+ void callback (IAsyncResult ar)
+ {
+ HttpListener l = (HttpListener) ar.AsyncState;
+
+ HttpListenerContext c = l.EndGetContext (ar);
+ HttpListenerRequest request = c.Request;
+
+ StreamReader r = new StreamReader (request.InputStream);
+ string sr =r.ReadToEnd ();
+ HttpListener2Test.Send (c.Response.OutputStream, "Miguel is love");
+ }
}
}
#endif