commit 01ce8dad3f25ec2d1786be69d3a1a7587bbb0b06 Author: uwaa Date: Fri Oct 25 05:45:41 2024 +0100 initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..65dad72 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.cs eol=crlf +*.txt eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44e1bbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vs +.vscode +bin +obj \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8fff7d0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "MiniHTTP"] + path = MiniHTTP + url = https://git.rape.pet/uwaa/MiniHTTP diff --git a/Example.sln b/Example.sln new file mode 100644 index 0000000..465e7a7 --- /dev/null +++ b/Example.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35027.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.csproj", "{7EAF8960-ABA7-4E12-B9AC-5FE3D0BAB0F6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiniHTTP", "MiniHTTP\MiniHTTP\MiniHTTP.csproj", "{12E5EAE8-2A60-4DC6-9D97-36CC54EDDBA6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7EAF8960-ABA7-4E12-B9AC-5FE3D0BAB0F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7EAF8960-ABA7-4E12-B9AC-5FE3D0BAB0F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12E5EAE8-2A60-4DC6-9D97-36CC54EDDBA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12E5EAE8-2A60-4DC6-9D97-36CC54EDDBA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {85D6E851-88E0-4C85-9B4F-AF0CB2005BDB} + EndGlobalSection +EndGlobal diff --git a/Example/Example.csproj b/Example/Example.csproj new file mode 100644 index 0000000..1341e0c --- /dev/null +++ b/Example/Example.csproj @@ -0,0 +1,20 @@ + + + Exe + net8.0 + false + enable + Debug + + + + + + + PreserveNewest + + + PreserveNewest + + + diff --git a/Example/Program.cs b/Example/Program.cs new file mode 100644 index 0000000..ad12fc5 --- /dev/null +++ b/Example/Program.cs @@ -0,0 +1,87 @@ +using System; +using System.IO; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using MiniHTTP.Websockets; +using MiniHTTP.Responses; +using MiniHTTP.Routing; + +namespace MiniHTTP.Example; + +internal partial class Program +{ + static void Main(string[] args) + { + Console.WriteLine("Loading certificate"); + X509Certificate2 cert = X509Certificate2.CreateFromPemFile("certs/example.net.crt", "certs/example.net.key"); + if (OperatingSystem.IsWindows()) + { + //Hack because SslStream is stupid on windows + using X509Certificate2 oldCert = cert; + cert = new X509Certificate2(oldCert.Export(X509ContentType.Pfx)); + } + + Console.WriteLine("Preparing listeners"); + Router router = CreateRouter(); + HttpServer httpServer = new HttpServer(80, null, router); + HttpServer httpsServer = new HttpServer(443, cert, router); + + Console.WriteLine("Ready on ports " + httpServer.Port + " and " +httpsServer.Port); + Task.WaitAll(httpServer.Start(), httpsServer.Start()); + } + + static Router CreateRouter() + { + Router router = new Router(NotFound); + router.Use("*", new CORS()); + router.Add(HttpMethod.GET, "test", Test); + router.Static("www-static"); + router.Static("www-dynamic"); + router.Add(HttpMethod.GET, "", Root); + + return router; + } + + static async Task Root(HttpRequest client, ParameterCollection parameters) + { + if (client.Headers.TryGetValue("Upgrade", out string? connection) && connection.Equals("websocket", StringComparison.OrdinalIgnoreCase)) + return await Websocket(client); + else + return new HttpContent("text/html", await File.ReadAllBytesAsync("www-static/index.htm")); + } + + static HttpResponse? Test(HttpRequest client, ParameterCollection parameters) + { + return new Redirect("/"); + } + + static HttpResponse? Test2(HttpRequest client, ParameterCollection parameters) + { + return new OK("Hello"); + } + + static HttpResponse NotFound(HttpRequest client, ParameterCollection parameters) + { + return new NotFound("File not found"); + } + + static async Task Websocket(HttpRequest client) + { + Websocket? ws = await client.UpgradeToWebsocket("test"); + if (ws == null) + return null; + + DataFrame payload = await ws.Read(); + + string result = payload.AsString(); + + if (payload.Opcode != WSOpcode.Close) + { + await ws.Write(true, $"Echoing message: \"{result}\""); + } + + ws.Close(CloseStatus.NormalClosure); + + return new Empty(); + } +} diff --git a/Example/certs/Test Root.crt b/Example/certs/Test Root.crt new file mode 100644 index 0000000..684a5f5 --- /dev/null +++ b/Example/certs/Test Root.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe6gAwIBAgIUG0ArzoB2Hz1DO7wFbUvIqogXhkEwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJVGVzdCBSb290MB4XDTI0MTAyNTAwNDYxMFoXDTI0MTEy +NDAwNDYxMFowFDESMBAGA1UEAwwJVGVzdCBSb290MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtc6B5D3X/RB+9BSVvnxkJ5ZV4uh8ZQn/8MykL9ILYPOr +WA3uCt6bCt07+6FSww1ii0fFwpEC8tCXel+ZaU4ds9MlVYfdp3d78TKt9rCy/cdr +YWK69KiawoPjynR+8B4d8ifztHsN+xYCl4zoZUW0O911RUGeV9aVFgtBN4a2dUbq +KUGEUkaj5rFMQWxPzdjtH8uCoBrVVBPLQ99qsiGC348ts0zvmb7MxN/nxgnnr9Sp +Fsloed32Yg8+sG9UxhHIF+ledlPaZtk8yAgsdCidy9bzBCpij684YuCIqVootZ5P +Wv0nkoIme8do71n4/sRqINxWwptbhx3rXRJqfkFDmwIDAQABo1AwTjAdBgNVHQ4E +FgQUfnn0b6tLeUyFPMUyKvclzlTeK20wHwYDVR0jBBgwFoAUfnn0b6tLeUyFPMUy +KvclzlTeK20wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAgjat+GIr +UVmJvK0BljojefmEL0oHILYm2xh8Tcd7otuQnKLFYBPNh1WizQiMPZvx8/Q1oH33 +qMjpqmwGglQc5xbm/kWhmmEp1Hvi37FeZk90e+qSgWUTH13OpTp7UcfmTEem4owb +BHEy3HrZrz2W1MSUQ3R4SnKGauOiYdwTbKoUHZGjEQ5o3kZVj8oLADx81XwvrM2n +x43T/n82rq8ufu20SV437VktYjfe5SCSiYS3wsohM5ZUEgLewyLVBHcQ5flHzAM6 +jSdjcxgvKVrxH0EyHsLLsnCWIe87CFOnmrN1YVJEf/8ag9iNybWdcg71/BiBeQko +hsqEFfiBjMd4Jg== +-----END CERTIFICATE----- diff --git a/Example/certs/Test Root.key b/Example/certs/Test Root.key new file mode 100644 index 0000000..1d9f4a3 --- /dev/null +++ b/Example/certs/Test Root.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1zoHkPdf9EH70 +FJW+fGQnllXi6HxlCf/wzKQv0gtg86tYDe4K3psK3Tv7oVLDDWKLR8XCkQLy0Jd6 +X5lpTh2z0yVVh92nd3vxMq32sLL9x2thYrr0qJrCg+PKdH7wHh3yJ/O0ew37FgKX +jOhlRbQ73XVFQZ5X1pUWC0E3hrZ1RuopQYRSRqPmsUxBbE/N2O0fy4KgGtVUE8tD +32qyIYLfjy2zTO+ZvszE3+fGCeev1KkWyWh53fZiDz6wb1TGEcgX6V52U9pm2TzI +CCx0KJ3L1vMEKmKPrzhi4IipWii1nk9a/SeSgiZ7x2jvWfj+xGog3FbCm1uHHetd +Emp+QUObAgMBAAECggEABFyIFZXXBaImRlK45beN0e+ziPYzOo7kp4rK1/IKn3CZ +CEuLp16zV3phNjMmwIXxeqfl7aBiJeytHzY5GiNrZ2UsVk+KslOVrJg4cvX50hUj +oiCm0Lgh8xw/R08UihjrqcodkmA7wKDeWD/87Aw7bttsNPu5aCALHMFEw9rYEhrv +KXlyVJ+Ccp3htIRn0Ox10yFdHN5Jb9Io39970QUPi8XPP7v3RTblwa3cxSepchEa +j/w+pcBkQA/EMZR8yjYqahfKpmH2rQGK+wus1YqZE4WIbLyFdCW8qSJWlm3eH9kr +0v/B2TtCjdDmxGoh+gqQYFY59eA0b8fy1gvf3vtXoQKBgQD3fBL5MMJTwieacKS6 +iiGp09R2bv1EbzGqI1qcWvW11bAKQ9EpxhhKtJfxZNgIp9OD7fSMjRf9BQDNJ/V5 +4juUXvDregp/CaGEfrp3r2+5sph90pjYwVILQNdE+cvCKZKG2Bz5BInpg4dkBGXO +NWAEgydRaNoXEpYYDDdvKc2PkQKBgQC8D+uFrluHc5YuFkHQQLUW4OP0//DvBjs2 +xyo50s+c1e+1/anaSANsUDzAcqUWy6sRo1fNCvzx5bMvXjmTMkuIUauzZ6dlwfDT +g2RTjocHpBpqiIcvGV1WeuA+g1r8l22yZ2Sm4xyVgPwnnTPutPupkIR7YpYAbW8B +6xoK63UiawKBgBg6fWEH9P5eM6JbBMV+YG1P36z4kLLyb9pIO8ay4Ps8QE/A8+kz +C43EwFtRlBTE2WBBG3/nEEIlCz8Kem3ESDDuWoezGvP07WsbPQYalsWHRoaK54vQ +4UdYwbpu+hO4HjA1WCDI4PeLeOXByHW3o/7NGDxQF4nKuAcCqyqm3QkBAoGAboVg +ocCVM+ZfBRi5dt0AT8C81zgu7RoZZJjpnO/iaUZlSOwZjRmzQU1qVqNJmDr7fzMi +n3LssnCOvLDAX1w4fZWZtaad/zRaBsP6Cw0BGCF+EMvJvolGjFNMRBDIQRfxNN6E +jXt9SfNyvQkrAwdDuyQeZ7DJfNjTWypCtNYpkZ8CgYEA01vGWqOfNm6JwWpG16bk +xJnnWsfMg1BdNLGEZzK+myf/cnxcUnTJIVLrSfJ6rDD5bVqviB09Zbs57l7k/e+C +f6X6ZazOQfr8dx9Qr+Z3rytehqKL+zWuSyaAyeyiuQF5Dcw5touWlJsBtjGveaW2 +yw079ym/DRE52zY5IMBUFNM= +-----END PRIVATE KEY----- diff --git a/Example/certs/example.net.crt b/Example/certs/example.net.crt new file mode 100644 index 0000000..884608c --- /dev/null +++ b/Example/certs/example.net.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDHTCCAgWgAwIBAgIUDBt289LdXev6twhyC/LYmr/YLSswDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJVGVzdCBSb290MB4XDTI0MTAyNTAwNDcwNloXDTI0MTEy +NDAwNDcwNlowFjEUMBIGA1UEAwwLZXhhbXBsZS5uZXQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCObaYcmizussr1oXDwqJvb9ecSs0yN5LtT/6x5h7IV +xnuq5R+In9H0/PLA6jL7QAwbtJUHt75l6stUXTJ5zoQpOjoxx62chouCgWZ9+dMd ++XhznwQLgnfB1UyJM0wIbNRatoWVK/BGZjCoeODWntR+urIqPXBQhsn1TIDbBoiV +lrjjTqDe1058bH1qd0WGTgpbJx1h2+w6vMvqSox3YEblF0QWOKTGhRRlC4umQHZm +DPY/he4AvnP8oHg6YdMw8Zhca3K91k73avbV6JxpKPOwo7XcRoTkAzZZpMzuA2zy +XvFjrOeCVhihkrGZWL/JKFT3F+860GDdWErkb5SUlyRzAgMBAAGjZTBjMB0GA1Ud +DgQWBBRSOoNBR4F0nBoZTlsEa2kno+KpbjAfBgNVHSMEGDAWgBR+efRvq0t5TIU8 +xTIq9yXOVN4rbTAWBgNVHREEDzANggtleGFtcGxlLm5ldDAJBgNVHRMEAjAAMA0G +CSqGSIb3DQEBCwUAA4IBAQBctQWE8qm9htwgUVwxbydg14YkUgCv9QPTCURQe2fP +1ecK8L5j5HfYCgB7ZdKdZfpUs89kCZNUBNn4GTCB1NnA3BoYxnAxELsYis2lI+TT +Jub0/oujh3dMrQZvI/0dcsmfyDvB7XzqDYuJo4tvsqUD7m5V6kqv6TdPK+YCnQ5F +AgAectokQvcWUdxvtVThScPXhHXyJsHJATfcmfpNCf1Tr4L+ePeB0dfrYRF+RVaV +hN0X+dVdWI8rL+wP2R/CjsSsqGoapth3vPIueSbBnaKj1buvDo+nvw1fCDcBQA9n +nOM/qlfeoZZIUK1wDOq5aO72bJdJ1byukYAGzWI4VvaQ +-----END CERTIFICATE----- diff --git a/Example/certs/example.net.key b/Example/certs/example.net.key new file mode 100644 index 0000000..f56a546 --- /dev/null +++ b/Example/certs/example.net.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCObaYcmizussr1 +oXDwqJvb9ecSs0yN5LtT/6x5h7IVxnuq5R+In9H0/PLA6jL7QAwbtJUHt75l6stU +XTJ5zoQpOjoxx62chouCgWZ9+dMd+XhznwQLgnfB1UyJM0wIbNRatoWVK/BGZjCo +eODWntR+urIqPXBQhsn1TIDbBoiVlrjjTqDe1058bH1qd0WGTgpbJx1h2+w6vMvq +Sox3YEblF0QWOKTGhRRlC4umQHZmDPY/he4AvnP8oHg6YdMw8Zhca3K91k73avbV +6JxpKPOwo7XcRoTkAzZZpMzuA2zyXvFjrOeCVhihkrGZWL/JKFT3F+860GDdWErk +b5SUlyRzAgMBAAECggEAGVDyIslgzTjojIqaqZw+v/VQkmleZSZQCdk7TgrJo8c4 ++iJp3X4S8sn3WEUItNIolNAfYVTOugznAWLjcvU7Vpyr9Wc5u8XKjHL1xdSfKwfJ +2jtcm7MgGEsSpJyCmkjF4i3pRp+dwNWvNnLt/BgVS0ViH9H14cpjoX9stAHQS05Q +PwsOClsqlRaC/jEwBQ3nR1sNzA90Sop/cH7VEnS8i7WZhyGFKcLWL3uuCatkDvn4 +PodnB4JFg4fwq2pn9749ohUt0JJquRK1Oa4epnZt2U6CDMIbFNUS3r17R8YFy3yV +C7EOb4yLLk38ind4Pm1YK998Q+Ia4R8MBjEoxAwsEQKBgQDDB5du/BQcTyET4znF +uVn8vUeiVaClW9oitts3bSa5Gcdf3WQwFRQAQ/qSk9LIz+ehO/qmHKggUStXREYu +KTGT/YPHNzXwSdDPey0tYP8MqO7HiNx/hox3cELUolopCCj0OZ8WOqo61cDeWF7O +UQ9vTmGHJf7i+to034j1nu05qQKBgQC69FJ/lZmH1ZX0GCWbQ/Su5NOcNQ7EduCB ++UISI2RGhApPUU9thdGv2FQIXBVAiGj947VaVLVS3GkPOANDwrfr7Rg9Ui+xE++A +oornNOIkvrG28KwE0Sov+6MbUeVQRrjd+V/lQ9Nzi33m2Liok5kz3gi/hCnMDIM0 +CIXcZn2WuwKBgDKT8W3S6dQ9oTJrJzxjyTaGT+GFm1fG7lc6XLePEw/F47K005q0 +nK9E8eK5e1ygrk1eJK6Xl/JpmnfTOPAXtsfOYzJy2wYp3oEwTJMMKJi75tDQaX6Z +AiynbG2AfSlO+G/90YgORr9jV9VRzaRr2TjgduJ5tBRhQd2cawRn5tWhAoGABeet +q2X4QXgXkmwo0+yjj9qebHKoksAGe1R6J8SCaE/HW5X/4j+1zc4RaWovKailWE+W +7NF8IK/hiZ+FSuCdmpAUketEol001WVM6dybv/ld959Gb6iDopxaHITLr2tsb2Zv +BvjLdvzS7zWtL3XqAt9ie1obT9ydUElsoPeDw/0CgYACKO+8BXqLlOggq/ETpIDx +KmCe/oo2aGqOpbHHHjy/MIXJFX3dMfzinbcM2iZxehOobIRX1UEbnxm5rqYcM/Eo +8lHqDAxm92JVqDQlw0g3H8OKMcqWc7gz8cPlgWVQO7kwmEJ9pM22gox6nSknHmC4 +oSWd5f1f7u8k8TX0L9HjLQ== +-----END PRIVATE KEY----- diff --git a/Example/www-static/favicon.ico b/Example/www-static/favicon.ico new file mode 100644 index 0000000..e2688c8 Binary files /dev/null and b/Example/www-static/favicon.ico differ diff --git a/Example/www-static/index.htm b/Example/www-static/index.htm new file mode 100644 index 0000000..d719152 --- /dev/null +++ b/Example/www-static/index.htm @@ -0,0 +1,10 @@ + + + + MiniHTTP Test + + + Websocket test + + + \ No newline at end of file diff --git a/Example/www-static/test.htm b/Example/www-static/test.htm new file mode 100644 index 0000000..dd050ab --- /dev/null +++ b/Example/www-static/test.htm @@ -0,0 +1,10 @@ + + + + Test + + + + Test + + \ No newline at end of file diff --git a/Example/www-static/websocket.js b/Example/www-static/websocket.js new file mode 100644 index 0000000..5f1dc2c --- /dev/null +++ b/Example/www-static/websocket.js @@ -0,0 +1,10 @@ +const ws = new WebSocket(`wss://${location.host}/`, "test"); +ws.onerror = (e) => { + throw e; +}; +ws.onopen = (event) => { + ws.send("Hello world"); +}; +ws.onmessage = (event) => { + console.log(event.data); +}; \ No newline at end of file diff --git a/MiniHTTP b/MiniHTTP new file mode 160000 index 0000000..8b29044 --- /dev/null +++ b/MiniHTTP @@ -0,0 +1 @@ +Subproject commit 8b290446717992a04a2a2cd26e1dfef125160d34