Added logging support and refactored some code
Log4J vuln inspired me to add some logging to this project :)))
This commit is contained in:
parent
a3a6a34e57
commit
b74707aac8
@ -8,35 +8,30 @@ using System.Text;
|
|||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
using RequestCallback = System.Action<Cuipod.Request, Cuipod.Response>;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Cuipod
|
namespace Cuipod
|
||||||
{
|
{
|
||||||
|
using RequestCallback = System.Action<Cuipod.Request, Cuipod.Response, ILogger<App>>;
|
||||||
|
|
||||||
public class App
|
public class App
|
||||||
{
|
{
|
||||||
|
private readonly TcpListener _listener = new TcpListener(IPAddress.Any, 1965);
|
||||||
|
private readonly Dictionary<string, RequestCallback> _requestCallbacks = new Dictionary<string, RequestCallback>();
|
||||||
|
private readonly byte[] _buffer = new byte[4096];
|
||||||
|
private readonly Decoder _decoder = Encoding.UTF8.GetDecoder();
|
||||||
|
|
||||||
private readonly string _directoryToServe;
|
private readonly string _directoryToServe;
|
||||||
private readonly TcpListener _listener;
|
|
||||||
private readonly X509Certificate2 _serverCertificate;
|
private readonly X509Certificate2 _serverCertificate;
|
||||||
private readonly Dictionary<string, RequestCallback> _requestCallbacks;
|
private readonly ILogger<App> _logger;
|
||||||
|
|
||||||
private RequestCallback _onBadRequestCallback;
|
private RequestCallback _onBadRequestCallback;
|
||||||
|
|
||||||
//somewhat flaky implementation - probably deprecate it
|
public App(string directoryToServe, X509Certificate2 certificate, ILogger<App> logger)
|
||||||
public App(string directoryToServe, string certificateFile, string privateRSAKeyFilePath)
|
|
||||||
{
|
{
|
||||||
_directoryToServe = directoryToServe;
|
_directoryToServe = directoryToServe;
|
||||||
_listener = new TcpListener(IPAddress.Any, 1965);
|
|
||||||
_requestCallbacks = new Dictionary<string, RequestCallback>();
|
|
||||||
_serverCertificate = CertificateUtils.LoadCertificate(certificateFile, privateRSAKeyFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public App(string directoryToServe, X509Certificate2 certificate)
|
|
||||||
{
|
|
||||||
|
|
||||||
_directoryToServe = directoryToServe;
|
|
||||||
_listener = new TcpListener(IPAddress.Any, 1965);
|
|
||||||
_requestCallbacks = new Dictionary<string, RequestCallback>();
|
|
||||||
_serverCertificate = certificate;
|
_serverCertificate = certificate;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnRequest(string route, RequestCallback callback)
|
public void OnRequest(string route, RequestCallback callback)
|
||||||
@ -49,13 +44,14 @@ namespace Cuipod
|
|||||||
_onBadRequestCallback = callback;
|
_onBadRequestCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
int status = 0;
|
|
||||||
Console.WriteLine("Serving capsule on 0.0.0.0:1965");
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_listener.Start();
|
_listener.Start();
|
||||||
|
|
||||||
|
_logger.LogInformation("Serving capsule on {0}", _listener.Server.LocalEndPoint.ToString());
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ProcessRequest(_listener.AcceptTcpClient());
|
ProcessRequest(_listener.AcceptTcpClient());
|
||||||
@ -63,15 +59,12 @@ namespace Cuipod
|
|||||||
}
|
}
|
||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
Console.WriteLine("SocketException: {0}", e);
|
_logger.LogError("SocketException: {0}", e);
|
||||||
status = 1;
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_listener.Stop();
|
_listener.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessRequest(TcpClient client)
|
private void ProcessRequest(TcpClient client)
|
||||||
@ -86,16 +79,16 @@ namespace Cuipod
|
|||||||
}
|
}
|
||||||
catch (AuthenticationException e)
|
catch (AuthenticationException e)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Exception: {0}", e.Message);
|
_logger.LogError("AuthenticationException: {0}", e.Message);
|
||||||
if (e.InnerException != null)
|
if (e.InnerException != null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
|
_logger.LogError("Inner exception: {0}", e.InnerException.Message);
|
||||||
}
|
}
|
||||||
Console.WriteLine("Authentication failed - closing the connection.");
|
_logger.LogError("Authentication failed - closing the connection.");
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Exception: {0}", e.Message);
|
_logger.LogError("IOException: {0}", e.Message);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -110,33 +103,37 @@ namespace Cuipod
|
|||||||
sslStream.AuthenticateAsServer(_serverCertificate, false, SslProtocols.Tls12 | SslProtocols.Tls13, false);
|
sslStream.AuthenticateAsServer(_serverCertificate, false, SslProtocols.Tls12 | SslProtocols.Tls13, false);
|
||||||
|
|
||||||
// Read a message from the client.
|
// Read a message from the client.
|
||||||
string rawURL = ReadRequest(sslStream);
|
string rawRequest = ReadRequest(sslStream);
|
||||||
|
|
||||||
Response response = new Response(_directoryToServe);
|
Response response = new Response(_directoryToServe);
|
||||||
|
|
||||||
if (rawURL == null)
|
if (rawRequest == null)
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("rawRequest is null - bad request");
|
||||||
response.Status = StatusCode.BadRequest;
|
response.Status = StatusCode.BadRequest;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(rawURL);
|
_logger.LogDebug("Raw request: \"{0}\"", rawRequest);
|
||||||
|
|
||||||
int protocolDelimiter = rawURL.IndexOf("://");
|
const string protocol= "gemini";
|
||||||
|
const string protocolSeparator = "://";
|
||||||
|
|
||||||
|
int protocolDelimiter = rawRequest.IndexOf(protocolSeparator);
|
||||||
if (protocolDelimiter == -1)
|
if (protocolDelimiter == -1)
|
||||||
{
|
{
|
||||||
response.Status = StatusCode.BadRequest;
|
response.Status = StatusCode.BadRequest;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
string protocol = rawURL.Substring(0, protocolDelimiter);
|
string requestProtocol = rawRequest.Substring(0, protocolDelimiter);
|
||||||
if (protocol != "gemini")
|
if (requestProtocol != protocol)
|
||||||
{
|
{
|
||||||
response.Status = StatusCode.BadRequest;
|
response.Status = StatusCode.BadRequest;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
string url = rawURL.Substring(protocolDelimiter + 3);
|
string url = rawRequest.Substring(protocolDelimiter + protocolSeparator.Length);
|
||||||
int domainNameDelimiter = url.IndexOf("/");
|
int domainNameDelimiter = url.IndexOf("/");
|
||||||
if (domainNameDelimiter == -1)
|
if (domainNameDelimiter == -1)
|
||||||
{
|
{
|
||||||
@ -144,22 +141,38 @@ namespace Cuipod
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
string domainName = url.Substring(0, domainNameDelimiter);
|
string domainName = url.Substring(0, domainNameDelimiter);
|
||||||
|
string baseURL = protocol + protocolSeparator + domainName;
|
||||||
|
|
||||||
Request request = new Request("gemini://" + domainName , url.Substring(domainNameDelimiter));
|
string route = url.Substring(domainNameDelimiter);
|
||||||
|
string parameters = "";
|
||||||
|
int parametersDelimiter = route.IndexOf("?");
|
||||||
|
if (parametersDelimiter != -1)
|
||||||
|
{
|
||||||
|
parameters = route.Substring(parametersDelimiter + 1);
|
||||||
|
route = route.Substring(0, parametersDelimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug("Request info:");
|
||||||
|
_logger.LogDebug("\tBaseURL: \"{0}\"", baseURL);
|
||||||
|
_logger.LogDebug("\tRoute: \"{0}\"", route);
|
||||||
|
_logger.LogDebug("\tParameters: \"{0}\"", parameters);
|
||||||
|
|
||||||
|
Request request = new Request(baseURL, route, parameters);
|
||||||
if (response.Status == StatusCode.Success)
|
if (response.Status == StatusCode.Success)
|
||||||
{
|
{
|
||||||
RequestCallback callback;
|
RequestCallback callback;
|
||||||
_requestCallbacks.TryGetValue(request.Route, out callback);
|
_requestCallbacks.TryGetValue(request.Route, out callback);
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
{
|
{
|
||||||
callback(request, response);
|
callback(request, response, _logger);
|
||||||
}
|
}
|
||||||
else if (_onBadRequestCallback != null)
|
else if (_onBadRequestCallback != null)
|
||||||
{
|
{
|
||||||
_onBadRequestCallback(request, response);
|
_onBadRequestCallback(request, response, _logger);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("Bad request: No suitable request callback");
|
||||||
response.Status = StatusCode.BadRequest;
|
response.Status = StatusCode.BadRequest;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@ -170,13 +183,10 @@ namespace Cuipod
|
|||||||
|
|
||||||
private string ReadRequest(SslStream sslStream)
|
private string ReadRequest(SslStream sslStream)
|
||||||
{
|
{
|
||||||
byte[] buffer = new byte[2048];
|
|
||||||
Decoder decoder = Encoding.UTF8.GetDecoder();
|
|
||||||
|
|
||||||
StringBuilder requestData = new StringBuilder();
|
StringBuilder requestData = new StringBuilder();
|
||||||
int bytes = sslStream.Read(buffer, 0, buffer.Length);
|
int bytes = sslStream.Read(_buffer, 0, _buffer.Length);
|
||||||
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
|
char[] chars = new char[_decoder.GetCharCount(_buffer, 0, bytes)];
|
||||||
decoder.GetChars(buffer, 0, bytes, chars, 0);
|
_decoder.GetChars(_buffer, 0, bytes, chars, 0);
|
||||||
string line = new string(chars);
|
string line = new string(chars);
|
||||||
if (line.EndsWith("\r\n"))
|
if (line.EndsWith("\r\n"))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,4 +4,8 @@
|
|||||||
<TargetFramework>net5.0</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
using System;
|
namespace Cuipod
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Cuipod
|
|
||||||
{
|
{
|
||||||
public class Request
|
public class Request
|
||||||
{
|
{
|
||||||
@ -10,20 +6,11 @@ namespace Cuipod
|
|||||||
public string Route { get; internal set; }
|
public string Route { get; internal set; }
|
||||||
public string Parameters { get; internal set; }
|
public string Parameters { get; internal set; }
|
||||||
|
|
||||||
public Request(string baseURL, string route)
|
internal Request(string baseURL, string route, string parameters)
|
||||||
{
|
{
|
||||||
BaseURL = baseURL;
|
BaseURL = baseURL;
|
||||||
|
Route = route;
|
||||||
int parametersDelimiter = route.IndexOf("?");
|
Parameters = parameters;
|
||||||
if (parametersDelimiter != -1)
|
|
||||||
{
|
|
||||||
Parameters = route.Substring(parametersDelimiter + 1);
|
|
||||||
Route = route.Substring(0, parametersDelimiter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Route = route;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,10 +8,10 @@ namespace Cuipod
|
|||||||
{
|
{
|
||||||
public StatusCode Status { get; set; }
|
public StatusCode Status { get; set; }
|
||||||
|
|
||||||
private string _directoryToServe;
|
private readonly string _directoryToServe;
|
||||||
private string _requestBody = "";
|
private string _requestBody = "";
|
||||||
|
|
||||||
public Response(string directoryToServe)
|
internal Response(string directoryToServe)
|
||||||
{
|
{
|
||||||
_directoryToServe = directoryToServe;
|
_directoryToServe = directoryToServe;
|
||||||
Status = StatusCode.Success;
|
Status = StatusCode.Success;
|
||||||
|
|||||||
@ -7,10 +7,17 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
|
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Cuipod\Cuipod.csproj" />
|
<ProjectReference Include="..\Cuipod\Cuipod.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="pages\index.gmi">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using Cuipod;
|
using Cuipod;
|
||||||
using Microsoft.Extensions.CommandLineUtils;
|
using Microsoft.Extensions.CommandLineUtils;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
|
||||||
@ -11,30 +12,25 @@ namespace CuipodExample
|
|||||||
{
|
{
|
||||||
CommandLineApplication commandLineApplication = new CommandLineApplication();
|
CommandLineApplication commandLineApplication = new CommandLineApplication();
|
||||||
commandLineApplication.HelpOption("-h | --help");
|
commandLineApplication.HelpOption("-h | --help");
|
||||||
CommandArgument directoryToServe = commandLineApplication.Argument(
|
|
||||||
"directory",
|
|
||||||
"Directory to server (required)"
|
|
||||||
);
|
|
||||||
CommandArgument certificateFile = commandLineApplication.Argument(
|
CommandArgument certificateFile = commandLineApplication.Argument(
|
||||||
"pfx certificate file",
|
"certificate",
|
||||||
"Path to certificate (required)"
|
"Path to certificate (required)"
|
||||||
);
|
);
|
||||||
CommandArgument pfxPassword = commandLineApplication.Argument(
|
CommandArgument privateRSAKeyFilePath = commandLineApplication.Argument(
|
||||||
"pfx password",
|
"key",
|
||||||
"pfx password"
|
"Path to private Pkcs8 RSA key (required)"
|
||||||
);
|
);
|
||||||
commandLineApplication.OnExecute(() =>
|
commandLineApplication.OnExecute(() =>
|
||||||
{
|
{
|
||||||
if (directoryToServe.Value == null || certificateFile.Value == null )
|
if (certificateFile.Value == null || privateRSAKeyFilePath.Value == null)
|
||||||
{
|
{
|
||||||
commandLineApplication.ShowHelp();
|
commandLineApplication.ShowHelp();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pass = (pfxPassword != null) ? pfxPassword.Value.ToString() : "";
|
X509Certificate2 cert = CertificateUtils.LoadCertificate(certificateFile.Value, privateRSAKeyFilePath.Value);
|
||||||
var cert = new X509Certificate2(certificateFile.Value.ToString(), pass);
|
|
||||||
|
|
||||||
return AppMain(directoryToServe.Value, cert);
|
return AppMain("pages/", cert);
|
||||||
});
|
});
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -49,18 +45,31 @@ namespace CuipodExample
|
|||||||
|
|
||||||
private static int AppMain(string directoryToServe, X509Certificate2 certificate)
|
private static int AppMain(string directoryToServe, X509Certificate2 certificate)
|
||||||
{
|
{
|
||||||
|
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
|
||||||
|
builder
|
||||||
|
.AddSimpleConsole(options =>
|
||||||
|
{
|
||||||
|
options.SingleLine = true;
|
||||||
|
options.TimestampFormat = "hh:mm:ss ";
|
||||||
|
})
|
||||||
|
.SetMinimumLevel(LogLevel.Debug)
|
||||||
|
);
|
||||||
|
|
||||||
|
ILogger<App> logger = loggerFactory.CreateLogger<App>();
|
||||||
|
|
||||||
App app = new App(
|
App app = new App(
|
||||||
directoryToServe,
|
directoryToServe,
|
||||||
certificate
|
certificate,
|
||||||
|
logger
|
||||||
);
|
);
|
||||||
|
|
||||||
// Serve files
|
// Serve files
|
||||||
app.OnRequest("/", (request, response) => {
|
app.OnRequest("/", (request, response, logger) => {
|
||||||
response.RenderFileContent("index.gmi");
|
response.RenderFileContent("index.gmi");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Input example
|
// Input example
|
||||||
app.OnRequest("/input", (request, response) => {
|
app.OnRequest("/input", (request, response, logger) => {
|
||||||
if (request.Parameters == null)
|
if (request.Parameters == null)
|
||||||
{
|
{
|
||||||
response.SetInputHint("Please enter something: ");
|
response.SetInputHint("Please enter something: ");
|
||||||
@ -74,7 +83,7 @@ namespace CuipodExample
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.OnRequest("/show", (request, response) => {
|
app.OnRequest("/show", (request, response, logger) => {
|
||||||
if (request.Parameters == null)
|
if (request.Parameters == null)
|
||||||
{
|
{
|
||||||
// redirect to input
|
// redirect to input
|
||||||
@ -89,18 +98,19 @@ namespace CuipodExample
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Or dynamically render content
|
// Or dynamically render content
|
||||||
app.OnRequest("/dynamic/content", (request, response) => {
|
app.OnRequest("/dynamic/content", (request, response, logger) => {
|
||||||
response.RenderPlainTextLine("# woah much content!");
|
response.RenderPlainTextLine("# woah much dynamic content!");
|
||||||
response.RenderPlainTextLine("More utilities to render content will come soon!");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Optional but nice. In case it is specified and client will do a bad route
|
// Optional but nice. In case it is specified and client will do a bad route
|
||||||
// request we will respond with Success status and render result from this lambda
|
// request we will respond with Success status and render result from this lambda
|
||||||
app.OnBadRequest((request, response) => {
|
app.OnBadRequest((request, response, logger) => {
|
||||||
response.RenderPlainTextLine("# Ohh No!!! Request is bad :(");
|
response.RenderPlainTextLine("# Ohh No!!! Request is bad :(");
|
||||||
});
|
});
|
||||||
|
|
||||||
return app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
CuipodExample/pages/index.gmi
Normal file
1
CuipodExample/pages/index.gmi
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Hello world!
|
||||||
56
README.md
56
README.md
@ -1,12 +1,16 @@
|
|||||||
# cuipod
|
# cuipod
|
||||||
Simple yet flexible framework for Gemini protocol servers
|
Simple yet flexible framework for Gemini protocol servers written in C# (.NET 5.0)
|
||||||
|
|
||||||
Framework is written in C# and based on .NET 5.0 framework.
|
|
||||||
The project is still in very early stage so bugs are expected. Feel free to raise an issue ticket or even raise PR!
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
For testing purposes you can generate certificate with this command
|
||||||
|
```
|
||||||
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout privatekey.key -out certificate.crt
|
||||||
|
```
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Cuipod;
|
using Cuipod;
|
||||||
|
|
||||||
namespace CuipodExample
|
namespace CuipodExample
|
||||||
@ -15,19 +19,35 @@ namespace CuipodExample
|
|||||||
{
|
{
|
||||||
static int Main(string[] args)
|
static int Main(string[] args)
|
||||||
{
|
{
|
||||||
|
X509Certificate2 cert = CertificateUtils.LoadCertificate(
|
||||||
|
"<dir_with_cert>/certificate.crt", // Path to certificate
|
||||||
|
"<dir_with_cert>/privatekey.key" // Path to private Pkcs8 RSA key
|
||||||
|
);
|
||||||
|
|
||||||
|
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
|
||||||
|
builder
|
||||||
|
.AddSimpleConsole(options =>
|
||||||
|
{
|
||||||
|
options.SingleLine = true;
|
||||||
|
options.TimestampFormat = "hh:mm:ss ";
|
||||||
|
})
|
||||||
|
.SetMinimumLevel(LogLevel.Debug)
|
||||||
|
);
|
||||||
|
ILogger<App> logger = loggerFactory.CreateLogger<App>();
|
||||||
|
|
||||||
App app = new App(
|
App app = new App(
|
||||||
"<directory_to_serve>/", // directory to serve
|
"pages/", // Directory to serve
|
||||||
"<dir_with_cert>/certificate.crt", // path to certificate
|
certificate,
|
||||||
"<dir_with_cert>/privatekey.key" // path to private Pkcs8 RSA key
|
logger
|
||||||
);
|
);
|
||||||
|
|
||||||
// Serve files
|
// Serve files
|
||||||
app.OnRequest("/", (request, response) => {
|
app.OnRequest("/", (request, response, logger) => {
|
||||||
response.RenderFileContent("index.gmi");
|
response.RenderFileContent("index.gmi");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Input example
|
// Input example
|
||||||
app.OnRequest("/input", (request, response) => {
|
app.OnRequest("/input", (request, response, logger) => {
|
||||||
if (request.Parameters == null)
|
if (request.Parameters == null)
|
||||||
{
|
{
|
||||||
response.SetInputHint("Please enter something: ");
|
response.SetInputHint("Please enter something: ");
|
||||||
@ -41,7 +61,7 @@ namespace CuipodExample
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.OnRequest("/show", (request, response) => {
|
app.OnRequest("/show", (request, response, logger) => {
|
||||||
if (request.Parameters == null)
|
if (request.Parameters == null)
|
||||||
{
|
{
|
||||||
// redirect to input
|
// redirect to input
|
||||||
@ -56,19 +76,25 @@ namespace CuipodExample
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Or dynamically render content
|
// Or dynamically render content
|
||||||
app.OnRequest("/dynamic/content", (request, response) => {
|
app.OnRequest("/dynamic/content", (request, response, logger) => {
|
||||||
response.RenderPlainTextLine("# woah much content!");
|
response.RenderPlainTextLine("# woah much dynamic content!");
|
||||||
response.RenderPlainTextLine("More utilities to render content will come soon!");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Optional but nice. In case it is specified and client will do a bad route
|
// Optional but nice. In case it is specified and client will do a bad route
|
||||||
// request we will respond with Success status and render result from this lambda
|
// request we will respond with Success status and render result from this lambda
|
||||||
app.OnBadRequest((request, response) => {
|
app.OnBadRequest((request, response, logger) => {
|
||||||
response.RenderPlainTextLine("# Ohh No!!! Request is bad :(");
|
response.RenderPlainTextLine("# Ohh No!!! Request is bad :(");
|
||||||
});
|
});
|
||||||
|
|
||||||
return app.Run();
|
app.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Full example project is in `CuipodExample` directory
|
||||||
|
|
||||||
|
# Contribution
|
||||||
|
Feel free to raise an issue ticket or even raise a pull request.
|
||||||
Reference in New Issue
Block a user