public void TestIssue23() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() { // 10MiB headers for testing MaxRequestHeaderSize = 1024 * 1024 * 10 } .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute(new RegressionDummyHandler())) ) { var req = System.Net.WebRequest.CreateHttp($"http://127.0.0.1:{server.Port}/reporttarget"); req.Method = "GET"; // Add a bunch of nonsense headers // to artificially inflate the header size for (var i = 0; i < 1000; i++) { req.Headers.Add($"X-{i}", new string((char)('A' + (i % ('Z' - 'A'))), 100)); } using (var res = (HttpWebResponse)req.GetResponse()) { if (res.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception($"Bad status code: {res.StatusCode}"); } string result; using (var sr = new System.IO.StreamReader(res.GetResponseStream())) result = sr.ReadToEnd(); } } }
public void TestRoutingWithManualRoutes() { var inst = new ControllerItems.ApiExampleController(); using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute( new ManualRoutingController() // We need to supply the function argument types, as C# does not support // automatic inference of these .Wire <IHttpContext>("GET /api/v1/entry", inst.Index) .Wire <IHttpContext, int, string>("GET /api/v1/entry/{id}", inst.Index) .Wire <IHttpContext, int>("GET /api/v1/entry/{id}/detail", inst.Cross) .Wire <int>("POST /api/v1/entry/{id}", inst.Update) .Wire <IHttpContext>("GET /api/v1/entry/detail", inst.Detail) .Wire <IHttpContext, int>("GET|POST /api/v1/entry/detail/{id}", inst.Detail) // If the methods have no arguments, we do not need to supply types .Wire("* /home", new ControllerItems.HomeController().Index) .Wire("GET /api/v1/wait", new ControllerItems.WaitExample().Index) .ToRoute() ))) { CommonTesting(server); } }
/// <summary> /// Helper method to ensure that the different ways of routing /// result in the same setup /// </summary> /// <param name="server">The server runner instance</param> private void CommonTesting(ServerRunner server) { Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/")); Assert.AreEqual(HttpStatusCode.OK, server.GetStatusCode("/home")); Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/xyz")); Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/home1")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/home", "GET")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/home", "XYZ")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/home1", "XYZ")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/home", "XYZ")); Assert.AreEqual(ControllerItems.ENTRY_DEFAULT_INDEX, server.GetStatusMessage("/api/v1/entry")); Assert.AreEqual(ControllerItems.ENTRY_INDEX_ID, server.GetStatusMessage("/api/v1/entry/4")); Assert.AreEqual(HttpStatusCode.BadRequest, server.GetStatusCode("/api/v1/entry/x")); Assert.AreEqual(ControllerItems.ENTRY_DETAIL_INDEX, server.GetStatusMessage("/api/v1/entry/detail")); Assert.AreEqual(ControllerItems.ENTRY_DETAIL_ID, server.GetStatusMessage("/api/v1/entry/detail/7")); Assert.AreEqual(HttpStatusCode.BadRequest, server.GetStatusCode("/api/v1/entry/detail/y")); Assert.AreEqual(ControllerItems.ENTRY_DETAIL_CROSS, server.GetStatusMessage("/api/v1/entry/7/detail")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1/")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1/home")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1/xyz")); Assert.AreEqual(ControllerItems.WAIT_INDEX, server.GetStatusMessage("/api/v1/wait", "GET")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.MethodNotAllowed), server.GetStatusMessage("/api/v1/wait", "POST")); Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/api/v1/4/detail")); }
public void TestRoutingWithoutDefaultController() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute( typeof(ControllerItems) .GetNestedTypes() .ToRoute()) )) { CommonTesting(server); } }
public void TestRoutingWithDefaultController() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute( typeof(ControllerItems) .GetNestedTypes() .ToRoute( new ControllerRouterConfig( typeof(ControllerItems.HomeController)) { HideDefaultController = false, Debug = true } )) )) { Assert.AreEqual(HttpStatusCode.OK, server.GetStatusCode("/")); Assert.AreEqual(HttpStatusCode.OK, server.GetStatusCode("/home")); Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/xyz")); Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/home1")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/", "GET")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/", "XYZ")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/home", "GET")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/home", "XYZ")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/home1", "XYZ")); Assert.AreEqual(ControllerItems.XYZ_HOME_INDEX, server.GetStatusMessage("/home", "XYZ")); Assert.AreEqual(ControllerItems.ENTRY_DEFAULT_INDEX, server.GetStatusMessage("/api/v1/entry")); Assert.AreEqual(ControllerItems.ENTRY_INDEX_ID, server.GetStatusMessage("/api/v1/entry/4")); Assert.AreEqual(HttpStatusCode.BadRequest, server.GetStatusCode("/api/v1/entry/x")); Assert.AreEqual(ControllerItems.ENTRY_DETAIL_INDEX, server.GetStatusMessage("/api/v1/entry/detail")); Assert.AreEqual(ControllerItems.ENTRY_DETAIL_ID, server.GetStatusMessage("/api/v1/entry/detail/7")); Assert.AreEqual(HttpStatusCode.BadRequest, server.GetStatusCode("/api/v1/entry/detail/y")); Assert.AreEqual(ControllerItems.ENTRY_DETAIL_CROSS, server.GetStatusMessage("/api/v1/entry/7/detail")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1/")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1/home")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.NotFound), server.GetStatusMessage("/api/v1/xyz")); Assert.AreEqual(ControllerItems.WAIT_INDEX, server.GetStatusMessage("/api/v1/wait", "GET")); Assert.AreEqual(HttpStatusMessages.DefaultMessage(HttpStatusCode.MethodNotAllowed), server.GetStatusMessage("/api/v1/wait", "POST")); Assert.AreEqual(HttpStatusCode.NotFound, server.GetStatusCode("/api/v1/4/detail")); } }
public void TestRoutingWithManualFromConfig2() { var filepath = System.IO.Path.Combine( System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) , "mvc.test2.txt"); var cfg = Ceen.Httpd.Cli.ConfigParser.ParseTextFile(filepath); using (var server = new ServerRunner( Ceen.Httpd.Cli.ConfigParser.ValidateConfig(cfg) .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) )) { CommonTesting(server); } }
public void TestRoutingWithManualRoutesWithoutInstancesPrefixed() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute( new ManualRoutingController() // Wire the full controllers, but use a custom prefix .WireController <ControllerItems.ApiExampleController>("/api/v1/entry") .WireController(new ControllerItems.HomeController(), "/home") .WireController(typeof(ControllerItems.WaitExample), "/api/v1/wait") .ToRoute() ))) { CommonTesting(server); } }
public void TestRoutingWithConflictingDefaultVerbs() { Assert.Throws <Exception>(() => { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddRoute( typeof(ConflictControllerItems2) .GetNestedTypes() .ToRoute( new ControllerRouterConfig() { Debug = true } )) )) { } }); }
public void TestRoutingWithRequirements() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute("/api/v1/wait", new RequirementControllerItems.TestHandler()) .AddRoute( new[] { typeof(RequirementControllerItems.WaitExample) } .ToRoute( new ControllerRouterConfig() { Debug = true } )) )) { Assert.AreEqual(RequirementControllerItems.WAIT_INDEX_GET, server.GetStatusMessage("/api/v1/wait", "GET")); Assert.AreEqual(RequirementControllerItems.WAIT_INDEX_DETAIL_GET, server.GetStatusMessage("/api/v1/wait/detail", "GET")); Assert.AreEqual(HttpStatusCode.InternalServerError, server.GetStatusCode("/api/v1/wait/detail", "HEAD")); } using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute("/api/v1/wait/detail", new RequirementControllerItems.TestHandler()) .AddRoute( new[] { typeof(RequirementControllerItems.WaitExample) } .ToRoute( new ControllerRouterConfig() { Debug = true } )) )) { Assert.AreEqual(HttpStatusCode.InternalServerError, server.GetStatusCode("/api/v1/wait", "GET")); Assert.AreEqual(RequirementControllerItems.WAIT_INDEX_DETAIL_GET, server.GetStatusMessage("/api/v1/wait/detail", "GET")); Assert.AreEqual(RequirementControllerItems.WAIT_INDEX_DETAIL_HEAD, server.GetStatusMessage("/api/v1/wait/detail", "HEAD")); } }
public void TestResetProcessingTimeout() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() { MaxProcessingTimeSeconds = 1 } .AddLogger((context, exception, started, duration) => Task.Run(() => Console.WriteLine("Error: {0}", exception))) .AddRoute( new[] { typeof(DelayExample) } .ToRoute( new ControllerRouterConfig() { Debug = true } )) )) { Assert.AreEqual(HttpStatusCode.OK, server.GetStatusCode("/delaytarget?waitseconds=2&resettimer=true")); Assert.AreEqual(HttpStatusCode.RequestTimeout, server.GetStatusCode("/delaytarget?waitseconds=2&resettimer=false")); } }
public void TestIssue25() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() { // 10MiB headers for testing MaxRequestHeaderSize = 1024 * 1024 * 10 } .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute(new FormUnpackHandler())) ) { var req = System.Net.WebRequest.CreateHttp($"http://127.0.0.1:{server.Port}/reporttarget"); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; var data = Encoding.UTF8.GetBytes("key=1234"); using (var rq = req.GetRequestStream()) rq.Write(data, 0, data.Length); using (var res = (HttpWebResponse)req.GetResponse()) { if (res.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception($"Bad status code: {res.StatusCode}"); } string result; using (var sr = new System.IO.StreamReader(res.GetResponseStream())) result = sr.ReadToEnd(); var v = JsonConvert.DeserializeObject <Dictionary <string, string> >(result); if (!v.TryGetValue("key", out var k) || !string.Equals(k, "1234")) { throw new Exception($"Failed to auto-parse header: {res.StatusCode}"); } } } }
public void TestRoutingWithManualRoutesWithoutInstances() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute( new ManualRoutingController() // For types with overloaded methods, we need to specify which overload // The WireWith() helper saves us constantly referencing the type .WireWith <ControllerItems.ApiExampleController>() .Wire("GET /api/v1/entry", nameof(ControllerItems.ApiExampleController.Index), typeof(IHttpContext)) .Wire("GET /api/v1/entry/{id}", nameof(ControllerItems.ApiExampleController.Index), typeof(IHttpContext), typeof(int), typeof(string)) .Wire("GET /api/v1/entry/{id}/detail", nameof(ControllerItems.ApiExampleController.Cross)) .Wire("POST /api/v1/entry/{id}", nameof(ControllerItems.ApiExampleController.Update)) .Wire("GET /api/v1/entry/detail", nameof(ControllerItems.ApiExampleController.Detail), typeof(IHttpContext)) .Wire("GET|POST /api/v1/entry/detail/{id}", nameof(ControllerItems.ApiExampleController.Detail), typeof(IHttpContext), typeof(int)) .Wire <ControllerItems.HomeController>("* /home", nameof(ControllerItems.HomeController.Index)) .Wire <ControllerItems.WaitExample>("GET /api/v1/wait", nameof(ControllerItems.WaitExample.Index)) .ToRoute() ))) { CommonTesting(server); } }
public void TestSingleMultipart() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() { AutoParseMultipartFormData = true, } .AddLogger((context, exception, started, duration) => Task.Run(() => Console.WriteLine("Error: {0}", exception))) .AddRoute( new[] { typeof(ReportExample) } .ToRoute( new ControllerRouterConfig() { Debug = true } )) )) { var payload = " ... some text data ..."; string result = null; try { var boundary = "--test-boundary-1234"; var req = System.Net.WebRequest.CreateHttp($"http://127.0.0.1:{server.Port}/reporttarget"); req.Method = "POST"; req.ContentType = "multipart/form-data; boundary=" + boundary; using (var p = req.GetRequestStream()) { var data = System.Text.Encoding.UTF8.GetBytes( string.Join("\r\n", $"--{boundary}", "Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"", "Content-Type: text/plain", "", payload, $"--{boundary}--", "" ) ); p.Write(data, 0, data.Length); } using (var res = (System.Net.HttpWebResponse)req.GetResponse()) using (var sr = new System.IO.StreamReader(res.GetResponseStream())) result = sr.ReadToEnd(); } catch (System.Net.WebException wex) { if (wex.Response is System.Net.HttpWebResponse) { result = ((System.Net.HttpWebResponse)wex.Response).StatusDescription; } else { throw; } } Assert.AreEqual(payload, result); } }
public void TestIssue26() { using (var server = new ServerRunner( new Ceen.Httpd.ServerConfig() { // 10MiB headers for testing MaxRequestHeaderSize = 1024 * 1024 * 10 } .AddLogger(new Ceen.Httpd.Logging.StdOutErrors()) .AddRoute( new Type[] { typeof(QueryStringReader) } .ToRoute( new ControllerRouterConfig() { Debug = true } ) ) )) { var req = System.Net.WebRequest.CreateHttp($"http://127.0.0.1:{server.Port}/{nameof(QueryStringReader)}?key=1+2+3&k+e+y=1+1+1"); req.Method = "GET"; using (var res = (HttpWebResponse)req.GetResponse()) { if (res.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception($"Bad status code: {res.StatusCode}"); } string result; using (var sr = new System.IO.StreamReader(res.GetResponseStream())) result = sr.ReadToEnd(); var v = JsonConvert.DeserializeObject <Dictionary <string, string> >(result); if (!v.TryGetValue("parsekey", out var k) || !string.Equals(k, "1 2 3")) { throw new Exception($"Failed to parse key as input: {res.StatusCode}"); } if (!v.TryGetValue("urlkey", out k) || !string.Equals(k, "1 2 3")) { throw new Exception($"Failed to parse key in url: {res.StatusCode}"); } if (!v.TryGetValue("urlk_e_y", out k) || !string.Equals(k, "1 1 1")) { throw new Exception($"Failed to parse k+e+y in url: {res.StatusCode}"); } } req = System.Net.WebRequest.CreateHttp($"http://127.0.0.1:{server.Port}/{nameof(QueryStringReader)}"); req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; var data = Encoding.UTF8.GetBytes("key=1+2+3&k+e+y=1+1+1"); using (var rq = req.GetRequestStream()) rq.Write(data, 0, data.Length); using (var res = (HttpWebResponse)req.GetResponse()) { if (res.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception($"Bad status code: {res.StatusCode}"); } string result; using (var sr = new System.IO.StreamReader(res.GetResponseStream())) result = sr.ReadToEnd(); var v = JsonConvert.DeserializeObject <Dictionary <string, string> >(result); if (!v.TryGetValue("parsekey", out var k) || !string.Equals(k, "1 2 3")) { throw new Exception($"Failed to parse key as form input: {res.StatusCode}"); } if (!v.TryGetValue("formkey", out k) || !string.Equals(k, "1 2 3")) { throw new Exception($"Failed to parse key in form: {res.StatusCode}"); } if (!v.TryGetValue("formk_e_y", out k) || !string.Equals(k, "1 1 1")) { throw new Exception($"Failed to parse k+e+y in form: {res.StatusCode}"); } } } }