diff --git a/src/DemoControllers/DemoControllers.csproj b/src/DemoControllers/DemoControllers.csproj index bc1a4d9..49ff56e 100644 --- a/src/DemoControllers/DemoControllers.csproj +++ b/src/DemoControllers/DemoControllers.csproj @@ -123,6 +123,10 @@ + + {06A3D120-5923-4AD1-8411-7395A1EC6E94} + WebServer.Logging + {0B20D095-2896-41A6-865D-172DFD5ECC99} Webserver.Models diff --git a/src/DemoControllers/FromContentControllerSample.cs b/src/DemoControllers/FromContentControllerSample.cs index ac592b5..15d0e06 100644 --- a/src/DemoControllers/FromContentControllerSample.cs +++ b/src/DemoControllers/FromContentControllerSample.cs @@ -1,33 +1,40 @@ using Restup.DemoControllers.Model; +using Restup.Webserver; using Restup.Webserver.Attributes; using Restup.Webserver.Models.Contracts; using Restup.Webserver.Models.Schemas; -using System; -using System.Diagnostics; +using Restup.WebServer.Logging; namespace Restup.DemoControllers { [RestController(InstanceCreationType.PerCall)] public sealed class FromContentControllerSample { + private readonly ILogger _log; + + public FromContentControllerSample() + { + _log = LogManager.GetLogger(); + } + [UriFormat("/fromcontent")] public IPutResponse UpdateSomething([FromContent] FromContentData data) { - Debug.WriteLine($"Received counter value of {data.Counter}"); + _log.Debug($"Received counter value of {data.Counter}"); return new PutResponse(PutResponse.ResponseStatus.OK); } [UriFormat("/fromcontent")] public IPostResponse CreateSomething([FromContent] FromContentData data) { - Debug.WriteLine($"Received counter value of {data.Counter}"); + _log.Debug($"Received counter value of {data.Counter}"); return new PostResponse(PostResponse.ResponseStatus.Created, $"fromcontent/{data.Counter}"); } [UriFormat("/stringencoding")] public IGetResponse EncodingDecodingTest([FromContent] MoreComplexData data) { - Debug.WriteLine($"Received complex data with text {data.Text}"); + _log.Debug($"Received complex data with text {data.Text}"); return new GetResponse(GetResponse.ResponseStatus.OK, new MoreComplexData() { Text = data.Text }); } } diff --git a/src/HttpMessage/ServerRequestParsers/HttpRequestParser.cs b/src/HttpMessage/ServerRequestParsers/HttpRequestParser.cs index 6b57ff0..1c6af74 100644 --- a/src/HttpMessage/ServerRequestParsers/HttpRequestParser.cs +++ b/src/HttpMessage/ServerRequestParsers/HttpRequestParser.cs @@ -37,51 +37,44 @@ internal async Task ParseRequestStream(IInputStream re var httpStream = new HttpRequestStream(requestStream); var request = new MutableHttpServerRequest(); - try + var stream = await httpStream.ReadAsync(BUFFER_SIZE, InputStreamOptions.Partial); + byte[] streamData = stream.Data; + + var requestPipeline = GetPipeline(); + using (var pipeLineEnumerator = requestPipeline.GetEnumerator()) { - var stream = await httpStream.ReadAsync(BUFFER_SIZE, InputStreamOptions.Partial); - byte[] streamData = stream.Data; + pipeLineEnumerator.MoveNext(); + bool requestComplete = false; - var requestPipeline = GetPipeline(); - using (var pipeLineEnumerator = requestPipeline.GetEnumerator()) + while (!requestComplete) { - pipeLineEnumerator.MoveNext(); - bool requestComplete = false; + pipeLineEnumerator.Current.HandleRequestPart(streamData, request); + streamData = pipeLineEnumerator.Current.UnparsedData; - while (!requestComplete) + if (pipeLineEnumerator.Current.IsFinished) { - pipeLineEnumerator.Current.HandleRequestPart(streamData, request); - streamData = pipeLineEnumerator.Current.UnparsedData; - - if (pipeLineEnumerator.Current.IsFinished) + if (!pipeLineEnumerator.Current.IsSucceeded || + !pipeLineEnumerator.MoveNext()) { - if (!pipeLineEnumerator.Current.IsSucceeded || - !pipeLineEnumerator.MoveNext()) - { - break; - } + break; } - else - { - var newStreamdata = await httpStream.ReadAsync(BUFFER_SIZE, InputStreamOptions.Partial); - - if (!newStreamdata.ReadSuccessful) - { - break; - } + } + else + { + var newStreamdata = await httpStream.ReadAsync(BUFFER_SIZE, InputStreamOptions.Partial); - streamData = streamData.ConcatArray(newStreamdata.Data); + if (!newStreamdata.ReadSuccessful) + { + break; } + + streamData = streamData.ConcatArray(newStreamdata.Data); } } - - request.IsComplete = requestPipeline.All(p => p.IsSucceeded); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); } + request.IsComplete = requestPipeline.All(p => p.IsSucceeded); + return request; } } diff --git a/src/Restup.sln b/src/Restup.sln index 331ac33..3878207 100644 --- a/src/Restup.sln +++ b/src/Restup.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Webserver", "Webserver\Webserver.csproj", "{837B8FF3-DED6-4DC7-AD58-DBB0B3E44DD4}" EndProject @@ -29,8 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer.Logging", "WebSer EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - HttpMessage\HttpMessage.projitems*{837b8ff3-ded6-4dc7-ad58-dbb0b3e44dd4}*SharedItemsImports = 4 HttpMessage\HttpMessage.projitems*{13aba022-a7c1-45b7-9e47-2bb74f2a7f9f}*SharedItemsImports = 13 + HttpMessage\HttpMessage.projitems*{837b8ff3-ded6-4dc7-ad58-dbb0b3e44dd4}*SharedItemsImports = 4 HttpMessage\HttpMessage.projitems*{d313f525-2d90-4bf5-8857-2698ee580a65}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/WebServer/Http/HttpServer.cs b/src/WebServer/Http/HttpServer.cs index 17f8448..db4a4af 100644 --- a/src/WebServer/Http/HttpServer.cs +++ b/src/WebServer/Http/HttpServer.cs @@ -45,16 +45,18 @@ public HttpServer(int serverPort) public async Task StartServerAsync() { + _log.Info($"Binding webserver to port {_port}..."); + await _listener.BindServiceNameAsync(_port.ToString()); - _log.Info($"Webserver listening on port {_port}"); + _log.Info($"Webserver listening on port {_port}."); } public void StopServer() { ((IDisposable)this).Dispose(); - _log.Info($"Webserver stopped listening on port {_port}"); + _log.Info($"Webserver stopped listening on port {_port}."); } private async void ProcessRequestAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) @@ -66,14 +68,28 @@ await Task.Run(async () => using (var inputStream = args.Socket.InputStream) { var request = await MutableHttpServerRequest.Parse(inputStream); + if (!request.IsComplete) + { + _log.Warn($"Request {request.Method} {request.Uri} aborted."); + return; + } + + if (_log.IsDebugEnabled()) + _log.Debug($"Handling request {request.Method} {request.Uri} from {args.Socket.Information.LocalAddress}."); + var httpResponse = await HandleRequestAsync(request); + if (_log.IsDebugEnabled()) + _log.Debug($"Request {request.Method} {request.Uri} from {args.Socket.Information.LocalAddress} handled, response status: {httpResponse.ResponseStatus}."); + await WriteResponseAsync(httpResponse, args.Socket); + if (_log.IsDebugEnabled()) + _log.Debug($"Responded to request {request.Method} {request.Uri}, {args.Socket.Information.LocalAddress}."); } } catch (Exception ex) { - _log.Error($"Exception while handling process: {ex.Message}"); + _log.Error($"Exception while handling request from {args.Socket.Information.LocalAddress}", ex); } finally { @@ -168,7 +184,9 @@ private static async Task WriteResponseAsync(HttpServerResponse response, Stream void IDisposable.Dispose() { + _log.Info("Disposing HttpServer..."); _listener.Dispose(); + _log.Info("HttpServer disposed."); } } } diff --git a/src/WebServer/LogManager.cs b/src/WebServer/LogManager.cs index 908ead7..65b221c 100644 --- a/src/WebServer/LogManager.cs +++ b/src/WebServer/LogManager.cs @@ -10,7 +10,7 @@ public static class LogManager static LogManager() { - _logFactory = new NullLogFactory(); + _logFactory = new DebugLogFactory(); } public static ILogger GetLogger() @@ -28,40 +28,47 @@ public static void SetLogFactory(ILogFactory logFactory) Interlocked.Exchange(ref _logFactory, logFactory); } - private class NullLogFactory : ILogFactory + private class DebugLogFactory : ILogFactory { - private readonly NullLogger _nullLogger; + private ILogger _debugLogger; - public NullLogFactory() + public DebugLogFactory() { - _nullLogger = new NullLogger(); + _debugLogger = new DebugLogger(); } - ILogger ILogFactory.GetLogger() + public void Dispose() { - return _nullLogger; + _debugLogger = null; } ILogger ILogFactory.GetLogger(string name) { - return _nullLogger; + return _debugLogger; } - public void Dispose() + ILogger ILogFactory.GetLogger() { + return _debugLogger; } } - private class NullLogger : AbstractLogger + public class DebugLogger : AbstractLogger { - protected override bool IsLogEnabled(LogLevel trace) => false; - - protected override void LogMessage(string message, LogLevel loggingLevel, params object[] args) + protected override bool IsLogEnabled(LogLevel trace) { + // Ignore level, log everything + return true; } protected override void LogMessage(string message, LogLevel loggingLevel, Exception ex) { + System.Diagnostics.Debug.WriteLine($"{DateTime.UtcNow.ToString("dd-MM-yyyy hh:mm:ss.fff")} {loggingLevel}: {message}. Exception: {Environment.NewLine} {ex}"); + } + + protected override void LogMessage(string message, LogLevel loggingLevel, params object[] args) + { + System.Diagnostics.Debug.WriteLine($"{DateTime.UtcNow.ToString("dd-MM-yyyy hh:mm:ss.fff")} {loggingLevel}: {(string.Format(message, args))}"); } } }