mirror of
https://github.com/AlexMacocian/MTSC.git
synced 2026-07-26 00:45:23 +00:00
120 lines
4.8 KiB
C#
120 lines
4.8 KiB
C#
using MTSC.Common.Http;
|
|
using MTSC.Common.Http.RoutingModules;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using static MTSC.Common.Http.HttpMessage;
|
|
|
|
namespace MTSC.Server.Handlers
|
|
{
|
|
public class HttpRoutingHandler : IHandler
|
|
{
|
|
ConcurrentDictionary<ClientData, HttpRequest> fragmentedMessages = new ConcurrentDictionary<ClientData, HttpRequest>();
|
|
private Dictionary<HttpMethods, Dictionary<string, (IHttpRoute, Func<HttpRequest, ClientData, bool>)>> moduleDictionary =
|
|
new Dictionary<HttpMethods, Dictionary<string, (IHttpRoute, Func<HttpRequest, ClientData, bool>)>>();
|
|
|
|
public HttpRoutingHandler()
|
|
{
|
|
foreach (HttpMethods method in (HttpMethods[])Enum.GetValues(typeof(HttpMethods)))
|
|
{
|
|
moduleDictionary[method] = new Dictionary<string, (IHttpRoute, Func<HttpRequest, ClientData, bool>)>();
|
|
}
|
|
}
|
|
|
|
public HttpRoutingHandler AddRoute(HttpMethods method, string uri, IHttpRoute routeModule, Func<HttpRequest, ClientData, bool> routeEnabler = null)
|
|
{
|
|
if(routeEnabler == null)
|
|
{
|
|
routeEnabler = (request, client) => { return true; };
|
|
}
|
|
moduleDictionary[method][uri] = (routeModule, routeEnabler);
|
|
return this;
|
|
}
|
|
|
|
void IHandler.ClientRemoved(Server server, ClientData client) { }
|
|
|
|
bool IHandler.HandleClient(Server server, ClientData client) => false;
|
|
|
|
bool IHandler.HandleReceivedMessage(Server server, ClientData client, Message message)
|
|
{
|
|
HttpRequest request;
|
|
/*
|
|
* If there's an existing fragmented request, get it from the storage.
|
|
*/
|
|
if (fragmentedMessages.ContainsKey(client))
|
|
{
|
|
request = fragmentedMessages[client];
|
|
request.AddToBody(message.MessageBytes);
|
|
}
|
|
else
|
|
{
|
|
request = HttpRequest.FromBytes(message.MessageBytes);
|
|
}
|
|
|
|
/*
|
|
* If the server hasn't received all the bytes specified by the request,
|
|
* add the request to storage and wait for the rest of bytes to be received.
|
|
*/
|
|
|
|
if (request.Headers.ContainsHeader(HttpMessage.EntityHeaders.ContentLength) &&
|
|
request.Body.Length < int.Parse(request.Headers[HttpMessage.EntityHeaders.ContentLength]))
|
|
{
|
|
fragmentedMessages[client] = request;
|
|
var continueResponse = new HttpResponse();
|
|
continueResponse.StatusCode = HttpMessage.StatusCodes.Continue;
|
|
server.QueueMessage(client, continueResponse.GetPackedResponse(true));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
fragmentedMessages.TryRemove(client, out _);
|
|
}
|
|
|
|
HttpResponse response = new HttpResponse();
|
|
if (request.Headers.ContainsHeader(HttpMessage.GeneralHeaders.Connection) &&
|
|
request.Headers[HttpMessage.GeneralHeaders.Connection].ToLower() == "close")
|
|
{
|
|
response.Headers[HttpMessage.GeneralHeaders.Connection] = "close";
|
|
client.ToBeRemoved = true;
|
|
}
|
|
else
|
|
{
|
|
response.Headers[HttpMessage.GeneralHeaders.Connection] = "keep-alive";
|
|
}
|
|
|
|
/*
|
|
* Now find if a routing module exists. If not let other handlers try and handle the message.
|
|
*/
|
|
if (moduleDictionary[request.Method].ContainsKey(request.RequestURI))
|
|
{
|
|
(var module, var routeEnabler) = moduleDictionary[request.Method][request.RequestURI];
|
|
if(routeEnabler.Invoke(request, client))
|
|
{
|
|
try
|
|
{
|
|
server.QueueMessage(client, module.HandleRequest(request, client, server).GetPackedResponse(true));
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
server.LogDebug("Exception: " + e.Message);
|
|
server.LogDebug("Stacktrace: " + e.StackTrace);
|
|
server.QueueMessage(client, new HttpResponse() { StatusCode = StatusCodes.InternalServerError }.GetPackedResponse(true));
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IHandler.HandleSendMessage(Server server, ClientData client, ref Message message) => false;
|
|
|
|
bool IHandler.PreHandleReceivedMessage(Server server, ClientData client, ref Message message) => false;
|
|
|
|
void IHandler.Tick(Server server) { }
|
|
}
|
|
}
|