diff --git a/Libraries/Core/Servers/Http/SptHttpListener.cs b/Libraries/Core/Servers/Http/SptHttpListener.cs index 08e11a6d..a18397d6 100644 --- a/Libraries/Core/Servers/Http/SptHttpListener.cs +++ b/Libraries/Core/Servers/Http/SptHttpListener.cs @@ -7,6 +7,7 @@ using Core.Models.Utils; using Core.Routers; using Core.Services; using Core.Utils; +using Server; using LogLevel = Core.Models.Spt.Logging.LogLevel; namespace Core.Servers.Http; @@ -19,8 +20,8 @@ public class SptHttpListener : IHttpListener // We want to read 1KB at a time, for most request this is already big enough private const int BodyReadBufferSize = 1024 * 1; - - + + protected readonly HttpRouter _router; protected readonly IEnumerable _serializers; protected readonly ISptLogger _logger; @@ -28,6 +29,7 @@ public class SptHttpListener : IHttpListener protected readonly HttpResponseUtil _httpResponseUtil; protected readonly LocalisationService _localisationService; protected readonly JsonUtil _jsonUtil; + public SptHttpListener( HttpRouter httpRouter, IEnumerable serializers, @@ -47,7 +49,8 @@ public class SptHttpListener : IHttpListener _jsonUtil = jsonUtil; } - private static readonly ImmutableHashSet SupportedMethods = ["GET", "PUT", "POST"]; + private static readonly ImmutableHashSet SupportedMethods = ["GET", "PUT", "POST"]; + public bool CanHandle(string _, HttpRequest req) { return SupportedMethods.Contains(req.Method); @@ -55,16 +58,18 @@ public class SptHttpListener : IHttpListener public void Handle(string sessionId, HttpRequest req, HttpResponse resp) { - switch (req.Method) { - case "GET": { + switch (req.Method) + { + case "GET": + { var response = GetResponse(sessionId, req, null); SendResponse(sessionId, req, resp, null, response); break; } // these are handled almost identically. case "POST": - case "PUT": { - + case "PUT": + { // Contrary to reasonable expectations, the content-encoding is _not_ actually used to // determine if the payload is compressed. All PUT requests are, and POST requests without // debug = 1 are as well. This should be fixed. @@ -88,6 +93,7 @@ public class SptHttpListener : IHttpListener readTask = req.Body.ReadAsync(memory).AsTask(); readTask.Wait(); } + string value; if (requestCompressed) { @@ -101,8 +107,9 @@ public class SptHttpListener : IHttpListener { value = Encoding.UTF8.GetString(totalRead[..readBytes].ToArray()); } - - if (!requestIsCompressed) { + + if (!requestIsCompressed) + { if (_logger.IsLogEnabled(LogLevel.Debug)) { _logger.Debug(value); @@ -114,7 +121,8 @@ public class SptHttpListener : IHttpListener break; } - default: { + default: + { _logger.Warning($"{_localisationService.GetText("unknown_request")}: {req.Method}"); break; } @@ -138,30 +146,36 @@ public class SptHttpListener : IHttpListener ) { if (body == null) + { body = new object(); + } var bodyInfo = _jsonUtil.Serialize(body); - if (IsDebugRequest(req)) { + if (IsDebugRequest(req)) + { // Send only raw response without transformation SendJson(resp, output, sessionID); if (_logger.IsLogEnabled(LogLevel.Debug)) { _logger.Debug($"Response: {output}"); } - // TODO: this.logRequest(req, output); + + LogRequest(req, output); return; } // Not debug, minority of requests need a serializer to do the job (IMAGE/BUNDLE/NOTIFY) var serialiser = _serializers.FirstOrDefault((x) => x.CanHandle(output)); - if (serialiser != null) { + if (serialiser != null) + { serialiser.Serialize(sessionID, req, resp, bodyInfo); - } else { + } + else + { // No serializer can handle the request (majority of requests dont), zlib the output and send response back SendZlibJson(resp, output, sessionID); } - // Console.WriteLine($"Response: {output}"); - + LogRequest(req, output); } @@ -170,7 +184,8 @@ public class SptHttpListener : IHttpListener * @param req Incoming request * @returns True if request is flagged as debug */ - protected bool IsDebugRequest(HttpRequest req) { + protected bool IsDebugRequest(HttpRequest req) + { return req.Headers.TryGetValue("responsecompressed", out var value) && value == "0"; } @@ -182,29 +197,32 @@ public class SptHttpListener : IHttpListener protected void LogRequest(HttpRequest req, string output) { // TODO: when do we want to log these? - //if (ProgramStatics.ENTRY_TYPE !== EntryType.RELEASE) { + if (ProgramStatics.ENTRY_TYPE() != EntryType.RELEASE) + { var log = new Response(req.Method, output); _requestLogger.Info($"RESPONSE={_jsonUtil.Serialize(log)}"); - //} + } } public string GetResponse(string sessionID, HttpRequest req, string? body) { var output = _router.GetResponse(req, sessionID, body, out var deserializedObject); /* route doesn't exist or response is not properly set up */ - if (string.IsNullOrEmpty(output)) { + if (string.IsNullOrEmpty(output)) + { _logger.Error(_localisationService.GetText("unhandled_response", req.Path.ToString())); _logger.Info(_jsonUtil.Serialize(deserializedObject)); output = _httpResponseUtil.GetBody(null, 404, $"UNHANDLED RESPONSE: {req.Path.ToString()}"); } - /* TODO: REQUEST LOGGER - if (ProgramStatics.ENTRY_TYPE !== EntryType.RELEASE) { - */ - // Parse quest info into object - - var log = new Request(req.Method, new RequestData(req.Path, req.Headers, deserializedObject)); - _requestLogger.Info($"REQUEST={_jsonUtil.Serialize(log)}"); - //} + + if (ProgramStatics.ENTRY_TYPE() != EntryType.RELEASE) + { + // Parse quest info into object + + var log = new Request(req.Method, new RequestData(req.Path, req.Headers, deserializedObject)); + _requestLogger.Info($"REQUEST={_jsonUtil.Serialize(log)}"); + } + return output; } @@ -214,7 +232,9 @@ public class SptHttpListener : IHttpListener resp.ContentType = "application/json"; resp.Headers.Append("Set-Cookie", $"PHPSESSID={sessionID}"); if (!string.IsNullOrEmpty(output)) + { resp.Body.WriteAsync(Encoding.UTF8.GetBytes(output)).AsTask().Wait(); + } resp.StartAsync().Wait(); resp.CompleteAsync().Wait(); } @@ -227,16 +247,18 @@ public class SptHttpListener : IHttpListener { deflateStream.WriteAsync(Encoding.UTF8.GetBytes(output)).AsTask().Wait(); } + var bytes = ms.ToArray(); resp.Body.WriteAsync(bytes, 0, bytes.Length).Wait(); } + resp.StartAsync().Wait(); resp.CompleteAsync().Wait(); } record Response(string Method, string jsonData); + record Request(string Method, object output); + record RequestData(string Url, object Headers, object Data); } - - diff --git a/Libraries/Core/Utils/FileUtil.cs b/Libraries/Core/Utils/FileUtil.cs index 44fc9326..a72e8cab 100644 --- a/Libraries/Core/Utils/FileUtil.cs +++ b/Libraries/Core/Utils/FileUtil.cs @@ -94,7 +94,6 @@ public class FileUtil( /// Source file to copy from /// /// Should destination file be overwritten - /// public void CopyFile(string copyFromPath, string destinationPath, bool overwrite = false) { // Check it exists first