154 lines
4.8 KiB
C#
154 lines
4.8 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Threading.Tasks;
|
|
using System.Net.Sockets;
|
|
using System.Net;
|
|
using Uwaa.HTTP.Websockets;
|
|
using Uwaa.HTTP.Routing;
|
|
|
|
namespace Uwaa.HTTP.Example;
|
|
|
|
static class Program
|
|
{
|
|
static void Main(string[] args)
|
|
{
|
|
Console.WriteLine("Loading test certificate");
|
|
X509Certificate cert = X509Certificate.CreateFromCertFile("certs/localhost.pfx");
|
|
|
|
Console.WriteLine("Preparing listeners");
|
|
Router router = CreateRouter();
|
|
HttpServer httpServer = new HttpServer(80, null, router);
|
|
HttpServer httpsServer = new HttpServer(443, cert, router);
|
|
|
|
httpServer.OnConnectionBegin += LogConnect;
|
|
httpServer.OnConnectionEnd += LogDisconnect;
|
|
httpsServer.OnConnectionBegin += LogConnect;
|
|
httpsServer.OnConnectionEnd += LogDisconnect;
|
|
|
|
httpServer.Start();
|
|
httpsServer.Start();
|
|
|
|
Console.WriteLine($"Ready on ports {httpServer.Port} and {httpsServer.Port}");
|
|
|
|
TestClient();
|
|
|
|
Task.Delay(-1).Wait();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates the URL router for the HTTP server.
|
|
/// </summary>
|
|
static Router CreateRouter()
|
|
{
|
|
//The order here matters
|
|
Router subpath = new Router();
|
|
subpath.Add("foo", new StaticEndpoint(HttpResponse.OK("A \"foo\" example sub page")));
|
|
subpath.Add("bar", new StaticEndpoint(HttpResponse.OK("A \"bar\" example sub page")));
|
|
|
|
Router router = new Router();
|
|
router.Add(LogRequest);
|
|
router.Add(new CORS());
|
|
router.Add("custom", new CustomRoute());
|
|
router.Add("subpath", subpath);
|
|
router.Add(new FileEndpoint("www-static") { Index = false });
|
|
router.Add(new FileEndpoint("www-dynamic") { Index = false });
|
|
router.Add("", Root);
|
|
router.Add(new StaticEndpoint(HttpResponse.NotFound("File not found")));
|
|
return router;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Example HTTP client request.
|
|
/// </summary>
|
|
static async void TestClient()
|
|
{
|
|
Console.WriteLine("Connecting");
|
|
|
|
//Make request
|
|
HttpRequest req = new HttpRequest(HttpMethod.GET, "/test.txt");
|
|
req.Fields.UserAgent = "test (Uwaa.HTTP)";
|
|
req.Fields.Connection = ConnectionType.Close;
|
|
|
|
//Send, get response
|
|
HttpResponse res = await HttpClient.Request("localhost", true, req);
|
|
string resText = res.Content?.AsText ?? "null";
|
|
Console.WriteLine("Got response: " + resText);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Logs a new connection to the console.
|
|
/// </summary>
|
|
static void LogConnect(TcpClient client)
|
|
{
|
|
Console.WriteLine($"{client.Client.RemoteEndPoint} connected");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Logs a disconnection to the console.
|
|
/// </summary>
|
|
static void LogDisconnect(IPEndPoint endpoint)
|
|
{
|
|
Console.WriteLine($"{endpoint} disconnected");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Logs a request to the console.
|
|
/// </summary>
|
|
static HttpResponse? LogRequest(HttpRequest req, HttpClientInfo info)
|
|
{
|
|
Console.WriteLine($"{info.Endpoint.Address}: {req.Method} {req.Path}");
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Root endpoint: /
|
|
/// </summary>
|
|
static async Task<HttpResponse?> Root(HttpRequest req, HttpClientInfo info)
|
|
{
|
|
if (req.IsWebsocket)
|
|
return Websocket(req, info);
|
|
|
|
byte[] indexFile = await File.ReadAllBytesAsync("www-static/index.html");
|
|
HttpContent html = new HttpContent(new MIMEType("text", "html"), indexFile);
|
|
return HttpResponse.OK(html);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Websocket endpoint
|
|
/// </summary>
|
|
static HttpResponse? Websocket(HttpRequest req, HttpClientInfo info)
|
|
{
|
|
return req.UpgradeToWebsocket(HandleWebsocket, "test");
|
|
}
|
|
|
|
static async Task<CloseStatus> HandleWebsocket(Websocket ws)
|
|
{
|
|
TimeSpan timeout = TimeSpan.FromMinutes(1);
|
|
|
|
DataFrame payload = await ws.Read().WaitAsync(timeout);
|
|
if (payload.Opcode != WSOpcode.Close)
|
|
{
|
|
string result = payload.AsString();
|
|
await ws.Write($"Echoing message: \"{result}\"").WaitAsync(timeout);
|
|
}
|
|
|
|
return CloseStatus.NormalClosure;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Custom route: /custom/{param1}/{param2}
|
|
/// </summary>
|
|
class CustomRoute : RouterBase
|
|
{
|
|
public override HttpMethod Method => HttpMethod.GET;
|
|
public override int Arguments => 2;
|
|
|
|
protected override Task<HttpResponse?> GetResponseInner(HttpRequest req, HttpClientInfo info, ArraySegment<string> path)
|
|
{
|
|
string param1 = path[0];
|
|
string param2 = path[1];
|
|
return Task.FromResult<HttpResponse?>(HttpResponse.OK($"Variable 1: {param1}\nVariable 2: {param2}"));
|
|
}
|
|
}
|
|
}
|