From d8b95baf187612aa19a5ff3942f95079957a5248 Mon Sep 17 00:00:00 2001 From: SandRock Date: Wed, 4 Sep 2013 19:39:06 +0200 Subject: [PATCH 1/5] remove statics and refactor a bit Removing static stuff to allow multiple instances. Intruducing HttpContext and IHttpHandler (does not compile yet) to separate concerns and allow IoC. --- uhttpsharp-demo/ConsoleTraceListener.cs | 109 ++++++++++++++++++++++++ uhttpsharp-demo/ErrorHandler.cs | 4 +- uhttpsharp-demo/Program.cs | 14 ++- uhttpsharp-demo/uhttpsharp-demo.csproj | 1 + uhttpsharp/HttpClient.cs | 10 ++- uhttpsharp/HttpContext.cs | 34 ++++++++ uhttpsharp/HttpRequestHandler.cs | 12 +-- uhttpsharp/HttpResponse.cs | 8 +- uhttpsharp/HttpRouter.cs | 35 +++++--- uhttpsharp/HttpServer.cs | 104 ++++++++++++++++------ uhttpsharp/IHttpHandler.cs | 30 +++++++ uhttpsharp/uhttpsharp.csproj | 2 + 12 files changed, 307 insertions(+), 56 deletions(-) create mode 100644 uhttpsharp-demo/ConsoleTraceListener.cs create mode 100644 uhttpsharp/HttpContext.cs create mode 100644 uhttpsharp/IHttpHandler.cs diff --git a/uhttpsharp-demo/ConsoleTraceListener.cs b/uhttpsharp-demo/ConsoleTraceListener.cs new file mode 100644 index 0000000..a176edd --- /dev/null +++ b/uhttpsharp-demo/ConsoleTraceListener.cs @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 uhttpsharp project - http://github.com/raistlinthewiz/uhttpsharp + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +namespace uhttpsharpdemo +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Text; + + /// + /// Logs tracing event to the with coloration. + /// + public class ConsoleTraceListener : TraceListener + { + private readonly object syncRoot = new object(); + + public static ConsoleTraceListener Bind() + { + var listener = Trace.Listeners.OfType().FirstOrDefault(); + + if (listener == null) + { + Trace.Listeners.Add(listener = new ConsoleTraceListener()); + } + + return listener; + } + + public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message) + { + base.TraceEvent(eventCache, source, eventType, id, message); + + lock (this.syncRoot) + { + var foreg = Console.ForegroundColor; + var backg = Console.BackgroundColor; + + switch (eventType) + { + case TraceEventType.Critical: + Console.ForegroundColor = ConsoleColor.White; + Console.BackgroundColor = ConsoleColor.Red; + break; + + case TraceEventType.Error: + Console.ForegroundColor = ConsoleColor.Red; + Console.BackgroundColor = ConsoleColor.White; + break; + + case TraceEventType.Verbose: + Console.ForegroundColor = ConsoleColor.Gray; + Console.BackgroundColor = ConsoleColor.White; + break; + + case TraceEventType.Warning: + Console.ForegroundColor = ConsoleColor.Yellow; + Console.BackgroundColor = ConsoleColor.Black; + break; + + case TraceEventType.Information: + case TraceEventType.Resume: + case TraceEventType.Start: + case TraceEventType.Stop: + case TraceEventType.Suspend: + case TraceEventType.Transfer: + default: + Console.ForegroundColor = ConsoleColor.White; + Console.BackgroundColor = ConsoleColor.Black; + break; + } + + Console.Write(eventType.ToString().Substring(0, 4).ToUpperInvariant() + " "); + + Console.ForegroundColor = ConsoleColor.White; + Console.BackgroundColor = ConsoleColor.Black; + + Console.WriteLine(message); + + Console.ForegroundColor = foreg; + Console.BackgroundColor = backg; + } + } + + public override void Write(string message) + { + } + + public override void WriteLine(string message) + { + } + } +} diff --git a/uhttpsharp-demo/ErrorHandler.cs b/uhttpsharp-demo/ErrorHandler.cs index 92d38ea..7a770e2 100644 --- a/uhttpsharp-demo/ErrorHandler.cs +++ b/uhttpsharp-demo/ErrorHandler.cs @@ -16,10 +16,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -using uhttpsharp; - namespace uhttpsharpdemo { + using uhttpsharp; + [HttpRequestHandlerAttributes("404")] public class ErrorHandler : HttpRequestHandler { diff --git a/uhttpsharp-demo/Program.cs b/uhttpsharp-demo/Program.cs index a70866d..051cd4f 100644 --- a/uhttpsharp-demo/Program.cs +++ b/uhttpsharp-demo/Program.cs @@ -19,6 +19,7 @@ using System; using System.Net.Sockets; using uhttpsharp; +using System.Net; namespace uhttpsharpdemo { @@ -26,12 +27,15 @@ internal static class Program { private static void Main() { + ConsoleTraceListener.Bind(); + + HttpServer server = null; for (var port = 8000; port <= 65535; ++port) { - HttpServer.Instance.Port = port; + server = new HttpServer(IPAddress.Loopback, port); try { - HttpServer.Instance.StartUp(); + server.Start(); } catch (SocketException) { @@ -39,7 +43,13 @@ private static void Main() } break; } + + Console.WriteLine("Hit return to exit"); Console.ReadLine(); + + Console.WriteLine("Stopping..."); + server.Dispose(); // TODO: this should be waiting for requests to end + Console.WriteLine("Stopped."); } } } \ No newline at end of file diff --git a/uhttpsharp-demo/uhttpsharp-demo.csproj b/uhttpsharp-demo/uhttpsharp-demo.csproj index 9c70de9..6cbdea9 100644 --- a/uhttpsharp-demo/uhttpsharp-demo.csproj +++ b/uhttpsharp-demo/uhttpsharp-demo.csproj @@ -47,6 +47,7 @@ Properties\AssemblyCommon.cs + diff --git a/uhttpsharp/HttpClient.cs b/uhttpsharp/HttpClient.cs index 37d59eb..4a93cf9 100644 --- a/uhttpsharp/HttpClient.cs +++ b/uhttpsharp/HttpClient.cs @@ -16,12 +16,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -using System.IO; -using System.Net.Sockets; -using System.Threading; - namespace uhttpsharp { + using System.IO; + using System.Net.Sockets; + using System.Threading; + public sealed class HttpClient { private readonly TcpClient _client; @@ -69,7 +69,9 @@ private void ProcessInternal() } } else + { _client.Close(); + } } } } diff --git a/uhttpsharp/HttpContext.cs b/uhttpsharp/HttpContext.cs new file mode 100644 index 0000000..7444b55 --- /dev/null +++ b/uhttpsharp/HttpContext.cs @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 uhttpsharp project - http://github.com/raistlinthewiz/uhttpsharp + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +namespace uhttpsharp +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + public class HttpContext + { + public HttpServer Server { get; set; } + + public HttpRequest Request { get; set; } + + public HttpResponse Response { get; set; } + } +} diff --git a/uhttpsharp/HttpRequestHandler.cs b/uhttpsharp/HttpRequestHandler.cs index f87c645..66a7bff 100644 --- a/uhttpsharp/HttpRequestHandler.cs +++ b/uhttpsharp/HttpRequestHandler.cs @@ -16,15 +16,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -using System; - namespace uhttpsharp { - public class HttpRequestHandler + using System; + + public class HttpRequestHandler : IHttpHandler { - public virtual HttpResponse Handle(HttpRequest httpRequest) + public virtual void Handle(HttpContext context) { - throw new NotImplementedException(); + throw new NotSupportedException("This method must be overriden in a subclass."); } } @@ -35,7 +35,7 @@ public class HttpRequestHandlerAttributes : Attribute public HttpRequestHandlerAttributes(string functionName) { - Function = functionName; + this.Function = functionName; } } } \ No newline at end of file diff --git a/uhttpsharp/HttpResponse.cs b/uhttpsharp/HttpResponse.cs index 4317b1f..01df087 100644 --- a/uhttpsharp/HttpResponse.cs +++ b/uhttpsharp/HttpResponse.cs @@ -46,10 +46,12 @@ public HttpResponse(HttpResponseCode code, string content) : this(code, "text/html; charset=utf-8", StringToStream(content)) { } + public HttpResponse(string contentType, Stream contentStream) : this(HttpResponseCode.Ok, contentType, contentStream) { } + private HttpResponse(HttpResponseCode code, string contentType, Stream contentStream) { Protocol = "HTTP/1.1"; @@ -68,6 +70,7 @@ public static HttpResponse CreateWithMessage(HttpResponseCode code, string messa "{0}

{1}


{0}{2}", HttpServer.Instance.Banner, message, body)); } + private static Stream StringToStream(string content) { var stream = new MemoryStream(); @@ -76,10 +79,11 @@ private static Stream StringToStream(string content) writer.Flush(); return stream; } + public void WriteResponse(Stream stream) { - var writer = new StreamWriter(stream) {NewLine = "\r\n"}; - writer.WriteLine("{0} {1} {2}", Protocol, (int) Code, _responseTexts[(int) Code]); + var writer = new StreamWriter(stream) { NewLine = "\r\n" }; + writer.WriteLine("{0} {1} {2}", Protocol, (int)Code, _responseTexts[(int)Code]); writer.WriteLine("Date: {0}", DateTime.UtcNow.ToString("R")); writer.WriteLine("Server: {0}", HttpServer.Instance.Banner); writer.WriteLine("Connection: {0}", CloseConnection ? "close" : "Keep-Alive"); diff --git a/uhttpsharp/HttpRouter.cs b/uhttpsharp/HttpRouter.cs index 27a5da0..fe85611 100644 --- a/uhttpsharp/HttpRouter.cs +++ b/uhttpsharp/HttpRouter.cs @@ -22,11 +22,11 @@ namespace uhttpsharp { - internal sealed class HttpRouter + public sealed class HttpRouter { - private readonly Dictionary _handlers = new Dictionary(); + private readonly Dictionary _handlers = new Dictionary(); - public HttpRouter() + internal HttpRouter() { RegisterHandlers(); } @@ -35,10 +35,12 @@ private HttpResponse DefaultError() { return HttpResponse.CreateWithMessage(HttpResponseCode.NotFound, "Not Found"); } + private HttpResponse DefaultIndex() { return HttpResponse.CreateWithMessage(HttpResponseCode.Ok, "Welcome to uhttpsharp!"); } + public HttpResponse Route(HttpRequest request) { var function = request.Parameters.Function; @@ -49,31 +51,38 @@ public HttpResponse Route(HttpRequest request) RouteToFunction(request, "404") ?? DefaultError(); } - private HttpResponse RouteToFunction(HttpRequest request, string function) + + private HttpContext RouteToFunction(HttpRequest request, string function) { - HttpRequestHandler handler; + IHttpHandler handler; + var context = new HttpContext + { + Request = request, + }; + if (_handlers.TryGetValue(function, out handler)) - return handler.Handle(request); - return null; + context.Response = handler.Handle(request); + return ; } + private void RegisterHandlers() { - foreach (var t in Assembly.GetEntryAssembly().GetTypes()) + foreach (var type in Assembly.GetEntryAssembly().GetTypes()) { - if (t.IsSubclassOf(typeof(HttpRequestHandler))) + if (type.IsSubclassOf(typeof(HttpRequestHandler))) { try { - var attributes = t.GetCustomAttributes(typeof(HttpRequestHandlerAttributes), true); + var attributes = type.GetCustomAttributes(typeof(HttpRequestHandlerAttributes), true); if (attributes.Length > 0) { - var handler = (HttpRequestHandler)Activator.CreateInstance(t); + var handler = (HttpRequestHandler)Activator.CreateInstance(type); _handlers.Add(((HttpRequestHandlerAttributes)attributes[0]).Function, handler); } } - catch (Exception e) + catch (Exception ex) { - Console.WriteLine(string.Format("Exception during activating the IHttpRequestHandler: {0} - {1}", t, e)); + Console.WriteLine(string.Format("Exception during activating the IHttpRequestHandler: {0} - {1}", type, ex)); } } } diff --git a/uhttpsharp/HttpServer.cs b/uhttpsharp/HttpServer.cs index ee3ae38..dbd0b50 100644 --- a/uhttpsharp/HttpServer.cs +++ b/uhttpsharp/HttpServer.cs @@ -16,54 +16,104 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -using System; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Threading; - namespace uhttpsharp { - public sealed class HttpServer - { - public static readonly HttpServer Instance = new HttpServer(); + using System; + using System.Net; + using System.Net.Sockets; + using System.Reflection; + using System.Threading; + using System.Diagnostics; - public int Port = 80; + public class HttpServer : IDisposable + { public string Banner = string.Empty; + private bool isDisposed; + private TcpListener listener; + private bool isActive; + private Thread serverThread; + + public HttpServer(IPAddress address, int port) + { + this.Address = address; + this.Port = port; + this.Banner = string.Format("uhttpsharp {0}", Assembly.GetExecutingAssembly().GetName().Version); + this.Router = new HttpRouter(); + } - private TcpListener _listener; - private bool _isActive; + public IPAddress Address { get; set; } - public string Address + public int Port { get; set; } + + public HttpRouter Router { get; private set; } + + public void Start() { - get { return string.Format("{0}:{1}", IPAddress.Loopback, Port); } + if (this.isActive) + return; + this.listener = new TcpListener(IPAddress.Loopback, Port); + this.listener.Start(); + this.serverThread = new Thread(Listen) + { + IsBackground = true, + }; + this.serverThread.Start(); } - private HttpServer() + public void Dispose() { - Banner = string.Format("uhttpsharp {0}", Assembly.GetExecutingAssembly().GetName().Version); + this.Dispose(true, TimeSpan.FromSeconds(60D)); + GC.SuppressFinalize(this); } - public void StartUp() + public void Dispose(TimeSpan timeout) { - if (_isActive) - return; - _listener = new TcpListener(IPAddress.Loopback, Port); - _listener.Start(); - var serverThread = new Thread(Listen) {IsBackground = true}; - serverThread.Start(); + this.Dispose(true, timeout); + GC.SuppressFinalize(this); + } + + public override string ToString() + { + return this.GetType().Name + " " + this.Address.ToString() + ":" + this.Port.ToString(); + } + + protected virtual void Dispose(bool disposing, TimeSpan timeout) + { + if (!this.isDisposed) + { + if (disposing) + { + this.isActive = false; + + if (this.listener != null) + { + this.listener.Stop(); + this.listener = null; + } + + if (this.serverThread != null) + { + this.serverThread.Join(timeout); + this.serverThread = null; + } + } + + this.isDisposed = true; + } } private void Listen() { - _isActive = true; + this.isActive = true; - Console.WriteLine(string.Format("Embedded httpserver started.. [{0}:{1}]", IPAddress.Loopback, Port)); + Trace.TraceInformation(this.ToString() + " is now listenning."); - while (_isActive) + while (this.isActive) { - new HttpClient(_listener.AcceptTcpClient()); + new HttpClient(listener.AcceptTcpClient()); } + + Trace.TraceInformation(this.ToString() + " is not listenning anymore."); } } } \ No newline at end of file diff --git a/uhttpsharp/IHttpHandler.cs b/uhttpsharp/IHttpHandler.cs new file mode 100644 index 0000000..50f8434 --- /dev/null +++ b/uhttpsharp/IHttpHandler.cs @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 uhttpsharp project - http://github.com/raistlinthewiz/uhttpsharp + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +namespace uhttpsharp +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + public interface IHttpHandler + { + void Handle(HttpContext context); + } +} diff --git a/uhttpsharp/uhttpsharp.csproj b/uhttpsharp/uhttpsharp.csproj index 0de8e1b..4ef2c2b 100644 --- a/uhttpsharp/uhttpsharp.csproj +++ b/uhttpsharp/uhttpsharp.csproj @@ -44,11 +44,13 @@ Properties\AssemblyCommon.cs
+ + From 2dd0746fb648981a53948de5a6d56957eb2e94d8 Mon Sep 17 00:00:00 2001 From: SandRock Date: Thu, 5 Sep 2013 11:45:15 +0200 Subject: [PATCH 2/5] updated readme --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index d213a60..44849fb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@ # uhttpsharp +## In this branch + +A few changes I'm making for another project: + +* Allow multiple instances (on multiple TCP/IP ports) +* Allow bit of IoC +* Use lambdas to define routes +* Convert the HttpHandler class to a IHttpHandler interface +* Create a HttpContext class to simplify IHttpHandler + +__Source code is not usable at this time (compile errors).__ + +## License + A very lightweight & simple embedded http server for c# Copyright (C) 2011 uhttpsharp project From 7a9ef1506a7ce7dd1cee6986c1ba62d2608c0cbc Mon Sep 17 00:00:00 2001 From: sandrock Date: Mon, 16 Dec 2013 20:52:22 +0100 Subject: [PATCH 3/5] httpcontext is now in da place --- uhttpsharp-demo/AboutHandler.cs | 4 ++-- uhttpsharp-demo/ErrorHandler.cs | 4 ++-- uhttpsharp-demo/FileHandler.cs | 39 ++++++++++++++++---------------- uhttpsharp-demo/IndexHandler.cs | 4 ++-- uhttpsharp/HttpClient.cs | 32 ++++++++++++++++++-------- uhttpsharp/HttpRequest.cs | 12 +++++----- uhttpsharp/HttpRequestHandler.cs | 2 +- uhttpsharp/HttpResponse.cs | 19 ++++++++-------- uhttpsharp/HttpRouter.cs | 36 +++++++++++++++-------------- uhttpsharp/HttpServer.cs | 6 ++++- uhttpsharp/IHttpHandler.cs | 2 +- 11 files changed, 90 insertions(+), 70 deletions(-) diff --git a/uhttpsharp-demo/AboutHandler.cs b/uhttpsharp-demo/AboutHandler.cs index 5bbc501..b7fb880 100644 --- a/uhttpsharp-demo/AboutHandler.cs +++ b/uhttpsharp-demo/AboutHandler.cs @@ -23,9 +23,9 @@ namespace uhttpsharpdemo [HttpRequestHandlerAttributes("about")] public class AboutHandler : HttpRequestHandler { - public override HttpResponse Handle(HttpRequest httpRequest) + public override HttpResponse Handle(HttpContext context) { - return HttpResponse.CreateWithMessage(HttpResponseCode.Ok, "Sample http-request-handler"); + return HttpResponse.CreateWithMessage(context, HttpResponseCode.Ok, "Sample http-request-handler"); } } } \ No newline at end of file diff --git a/uhttpsharp-demo/ErrorHandler.cs b/uhttpsharp-demo/ErrorHandler.cs index 7a770e2..5f83264 100644 --- a/uhttpsharp-demo/ErrorHandler.cs +++ b/uhttpsharp-demo/ErrorHandler.cs @@ -23,9 +23,9 @@ namespace uhttpsharpdemo [HttpRequestHandlerAttributes("404")] public class ErrorHandler : HttpRequestHandler { - public override HttpResponse Handle(HttpRequest httpRequest) + public override HttpResponse Handle(HttpContext context) { - return new HttpResponse(HttpResponseCode.NotFound, "These are not the droids you are looking for."); + return new HttpResponse(context, HttpResponseCode.NotFound, "These are not the droids you are looking for."); } } } \ No newline at end of file diff --git a/uhttpsharp-demo/FileHandler.cs b/uhttpsharp-demo/FileHandler.cs index 3450fb8..cf2cf12 100644 --- a/uhttpsharp-demo/FileHandler.cs +++ b/uhttpsharp-demo/FileHandler.cs @@ -33,16 +33,26 @@ static FileHandler() { DefaultMimeType = "text/plain"; MimeTypes = new Dictionary - { - {".css", "text/css"}, - {".gif", "image/gif"}, - {".htm", "text/html"}, - {".html", "text/html"}, - {".jpg", "image/jpeg"}, - {".js", "application/javascript"}, - {".png", "image/png"}, - {".xml", "application/xml"}, - }; + { + {".css", "text/css"}, + {".gif", "image/gif"}, + {".htm", "text/html"}, + {".html", "text/html"}, + {".jpg", "image/jpeg"}, + {".js", "application/javascript"}, + {".png", "image/png"}, + {".xml", "application/xml"}, + }; + } + + public override HttpResponse Handle(HttpContext context) + { + var httpRoot = Path.GetFullPath(HttpRootDirectory ?? "."); + var requestPath = context.Request.Uri.AbsolutePath.TrimStart('/'); + var path = Path.GetFullPath(Path.Combine(httpRoot, requestPath)); + if (!File.Exists(path)) + return null; + return new HttpResponse(context, GetContentType(path), File.OpenRead(path)); } private string GetContentType(string path) @@ -52,14 +62,5 @@ private string GetContentType(string path) return MimeTypes[extension]; return DefaultMimeType; } - public override HttpResponse Handle(HttpRequest httpRequest) - { - var httpRoot = Path.GetFullPath(HttpRootDirectory ?? "."); - var requestPath = httpRequest.Uri.AbsolutePath.TrimStart('/'); - var path = Path.GetFullPath(Path.Combine(httpRoot, requestPath)); - if (!File.Exists(path)) - return null; - return new HttpResponse(GetContentType(path), File.OpenRead(path)); - } } } \ No newline at end of file diff --git a/uhttpsharp-demo/IndexHandler.cs b/uhttpsharp-demo/IndexHandler.cs index e6a31ed..e361758 100644 --- a/uhttpsharp-demo/IndexHandler.cs +++ b/uhttpsharp-demo/IndexHandler.cs @@ -23,9 +23,9 @@ namespace uhttpsharpdemo [HttpRequestHandlerAttributes("")] public class IndexHandler : HttpRequestHandler { - public override HttpResponse Handle(HttpRequest httpRequest) + public override HttpResponse Handle(HttpContext context) { - return new HttpResponse(HttpResponseCode.Ok, "Welcome to the Index. ☺"); + return new HttpResponse(context, HttpResponseCode.Ok, "Welcome to the Index. ☺"); } } } \ No newline at end of file diff --git a/uhttpsharp/HttpClient.cs b/uhttpsharp/HttpClient.cs index 4a93cf9..049837e 100644 --- a/uhttpsharp/HttpClient.cs +++ b/uhttpsharp/HttpClient.cs @@ -28,15 +28,20 @@ public sealed class HttpClient private readonly Stream _inputStream; private readonly Stream _outputStream; private readonly HttpRouter _router; + private readonly HttpContext context; - public HttpClient(TcpClient client) + public HttpClient(HttpContext context, TcpClient client) { - _client = client; - _inputStream = new BufferedStream(_client.GetStream()); - _outputStream = _client.GetStream(); - _router = new HttpRouter(); + this._client = client; + this.context = context; + this._inputStream = new BufferedStream(this._client.GetStream()); + this._outputStream = this._client.GetStream(); + this._router = new HttpRouter(); // TODO: extract router instantiation - var clientThread = new Thread(Process) {IsBackground = true}; + var clientThread = new Thread(this.Process) + { + IsBackground = true, + }; clientThread.Start(); } @@ -54,18 +59,25 @@ private void Process() // Socket exceptions on read will be re-thrown as IOException by BufferedStream } } + private void ProcessInternal() { while (_client.Connected) { var request = new HttpRequest(_inputStream); - if (request.Valid) + request.Process(context); + this.context.Request = request; + if (request.IsValid) { - var response = _router.Route(request); + var response = _router.Route(context); + this.context.Response = response; if (response != null) { - response.WriteResponse(_outputStream); - if (response.CloseConnection) _client.Close(); + response.WriteResponse(context, _outputStream); + if (response.CloseConnection) + { + _client.Close(); + } } } else diff --git a/uhttpsharp/HttpRequest.cs b/uhttpsharp/HttpRequest.cs index a16c4e1..cf6a16a 100644 --- a/uhttpsharp/HttpRequest.cs +++ b/uhttpsharp/HttpRequest.cs @@ -24,7 +24,7 @@ namespace uhttpsharp { public sealed class HttpRequest { - public bool Valid { get; private set; } + public bool IsValid { get; private set; } public Dictionary Headers { get; private set; } public HttpMethod HttpMethod { get; private set; } public string HttpProtocol { get; private set; } @@ -38,12 +38,12 @@ public HttpRequest(Stream stream) { Headers = new Dictionary(); _stream = stream; - Process(); + ////Process(); } - private void Process() + internal void Process(HttpContext context) { - Valid = false; + IsValid = false; // parse the http request var request = ReadLine(); @@ -69,7 +69,7 @@ private void Process() HttpProtocol = tokens[2]; URL = tokens[1]; - Uri = new Uri("http://" + HttpServer.Instance.Address + "/" + URL.TrimStart('/')); + Uri = new Uri("http://" + context.Server.Address + "/" + URL.TrimStart('/')); Parameters = new HttpRequestParameters(URL); Console.WriteLine(string.Format("[{0}:{1}] URL: {2}", HttpProtocol, HttpMethod, URL)); @@ -83,7 +83,7 @@ private void Process() Headers.Add(keys[0], keys[1]); } - Valid = true; + IsValid = true; } private string ReadLine() diff --git a/uhttpsharp/HttpRequestHandler.cs b/uhttpsharp/HttpRequestHandler.cs index 66a7bff..817f8c6 100644 --- a/uhttpsharp/HttpRequestHandler.cs +++ b/uhttpsharp/HttpRequestHandler.cs @@ -22,7 +22,7 @@ namespace uhttpsharp public class HttpRequestHandler : IHttpHandler { - public virtual void Handle(HttpContext context) + public virtual HttpResponse Handle(HttpContext context) { throw new NotSupportedException("This method must be overriden in a subclass."); } diff --git a/uhttpsharp/HttpResponse.cs b/uhttpsharp/HttpResponse.cs index 01df087..1adab54 100644 --- a/uhttpsharp/HttpResponse.cs +++ b/uhttpsharp/HttpResponse.cs @@ -42,17 +42,17 @@ public sealed class HttpResponse public HttpResponseCode Code { get; private set; } private Stream ContentStream { get; set; } - public HttpResponse(HttpResponseCode code, string content) - : this(code, "text/html; charset=utf-8", StringToStream(content)) + public HttpResponse(HttpContext context, HttpResponseCode code, string content) + : this(context, code, "text/html; charset=utf-8", StringToStream(content)) { } - public HttpResponse(string contentType, Stream contentStream) - : this(HttpResponseCode.Ok, contentType, contentStream) + public HttpResponse(HttpContext context, string contentType, Stream contentStream) + : this(context, HttpResponseCode.Ok, contentType, contentStream) { } - private HttpResponse(HttpResponseCode code, string contentType, Stream contentStream) + private HttpResponse(HttpContext context, HttpResponseCode code, string contentType, Stream contentStream) { Protocol = "HTTP/1.1"; ContentType = contentType; @@ -62,13 +62,14 @@ private HttpResponse(HttpResponseCode code, string contentType, Stream contentSt ContentStream = contentStream; } - public static HttpResponse CreateWithMessage(HttpResponseCode code, string message, string body = "") + public static HttpResponse CreateWithMessage(HttpContext context, HttpResponseCode code, string message, string body = "") { return new HttpResponse( + context, code, string.Format( "{0}

{1}


{0}{2}", - HttpServer.Instance.Banner, message, body)); + context.Server.Banner, message, body)); } private static Stream StringToStream(string content) @@ -80,12 +81,12 @@ private static Stream StringToStream(string content) return stream; } - public void WriteResponse(Stream stream) + public void WriteResponse(HttpContext context, Stream stream) { var writer = new StreamWriter(stream) { NewLine = "\r\n" }; writer.WriteLine("{0} {1} {2}", Protocol, (int)Code, _responseTexts[(int)Code]); writer.WriteLine("Date: {0}", DateTime.UtcNow.ToString("R")); - writer.WriteLine("Server: {0}", HttpServer.Instance.Banner); + writer.WriteLine("Server: {0}", context.Server.Banner); writer.WriteLine("Connection: {0}", CloseConnection ? "close" : "Keep-Alive"); writer.WriteLine("Content-Type: {0}", ContentType); writer.WriteLine("Content-Length: {0}", ContentStream.Length); diff --git a/uhttpsharp/HttpRouter.cs b/uhttpsharp/HttpRouter.cs index fe85611..0721d05 100644 --- a/uhttpsharp/HttpRouter.cs +++ b/uhttpsharp/HttpRouter.cs @@ -31,38 +31,40 @@ internal HttpRouter() RegisterHandlers(); } - private HttpResponse DefaultError() + private HttpResponse DefaultError(HttpContext context) { - return HttpResponse.CreateWithMessage(HttpResponseCode.NotFound, "Not Found"); + return HttpResponse.CreateWithMessage(context, HttpResponseCode.NotFound, "Not Found"); } - private HttpResponse DefaultIndex() + private HttpResponse DefaultIndex(HttpContext context) { - return HttpResponse.CreateWithMessage(HttpResponseCode.Ok, "Welcome to uhttpsharp!"); + return HttpResponse.CreateWithMessage(context, HttpResponseCode.Ok, "Welcome to uhttpsharp!"); } - public HttpResponse Route(HttpRequest request) + public HttpResponse Route(HttpContext context) { + var request = context.Request; var function = request.Parameters.Function; return - RouteToFunction(request, function) ?? - RouteToFunction(request, "*") ?? - (string.IsNullOrEmpty(function) ? (RouteToFunction(request, "") ?? DefaultIndex()) : null) ?? - RouteToFunction(request, "404") ?? - DefaultError(); + RouteToFunction(context, function) ?? + RouteToFunction(context, "*") ?? + (string.IsNullOrEmpty(function) ? (RouteToFunction(context, "") ?? DefaultIndex(context)) : null) ?? + RouteToFunction(context, "404") ?? + DefaultError(context); } - private HttpContext RouteToFunction(HttpRequest request, string function) + private HttpResponse RouteToFunction(HttpContext context, string function) { + var request = context.Request; IHttpHandler handler; - var context = new HttpContext - { - Request = request, - }; if (_handlers.TryGetValue(function, out handler)) - context.Response = handler.Handle(request); - return ; + { + context.Response = handler.Handle(context); + return context.Response; + } + + return null; } private void RegisterHandlers() diff --git a/uhttpsharp/HttpServer.cs b/uhttpsharp/HttpServer.cs index dbd0b50..d1a4414 100644 --- a/uhttpsharp/HttpServer.cs +++ b/uhttpsharp/HttpServer.cs @@ -110,7 +110,11 @@ private void Listen() while (this.isActive) { - new HttpClient(listener.AcceptTcpClient()); + var context = new HttpContext + { + Server = this, + }; + new HttpClient(context, listener.AcceptTcpClient()); } Trace.TraceInformation(this.ToString() + " is not listenning anymore."); diff --git a/uhttpsharp/IHttpHandler.cs b/uhttpsharp/IHttpHandler.cs index 50f8434..c7deb74 100644 --- a/uhttpsharp/IHttpHandler.cs +++ b/uhttpsharp/IHttpHandler.cs @@ -25,6 +25,6 @@ namespace uhttpsharp public interface IHttpHandler { - void Handle(HttpContext context); + HttpResponse Handle(HttpContext context); } } From 14746e91bc0937f2018c629bf24654cc8f34f8b2 Mon Sep 17 00:00:00 2001 From: sandrock Date: Thu, 19 Dec 2013 00:19:02 +0100 Subject: [PATCH 4/5] fixes shutdown exception --- uhttpsharp/HttpResponse.cs | 4 ++-- uhttpsharp/HttpServer.cs | 11 ++++++++++- uhttpsharp/uhttpsharp.csproj | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/uhttpsharp/HttpResponse.cs b/uhttpsharp/HttpResponse.cs index 1adab54..942ea68 100644 --- a/uhttpsharp/HttpResponse.cs +++ b/uhttpsharp/HttpResponse.cs @@ -42,8 +42,8 @@ public sealed class HttpResponse public HttpResponseCode Code { get; private set; } private Stream ContentStream { get; set; } - public HttpResponse(HttpContext context, HttpResponseCode code, string content) - : this(context, code, "text/html; charset=utf-8", StringToStream(content)) + public HttpResponse(HttpContext context, HttpResponseCode code, string content, string contentType = "text/html; charset=utf-8") + : this(context, code, contentType, StringToStream(content)) { } diff --git a/uhttpsharp/HttpServer.cs b/uhttpsharp/HttpServer.cs index d1a4414..4d60b6e 100644 --- a/uhttpsharp/HttpServer.cs +++ b/uhttpsharp/HttpServer.cs @@ -114,7 +114,16 @@ private void Listen() { Server = this, }; - new HttpClient(context, listener.AcceptTcpClient()); + try + { + var client = listener.AcceptTcpClient(); + new HttpClient(context, client); + } + catch (SocketException ex) + { + // "A blocking operation was interrupted by a call to WSACancelBlockingCall" + // occurs during shutdown + } } Trace.TraceInformation(this.ToString() + " is not listenning anymore."); diff --git a/uhttpsharp/uhttpsharp.csproj b/uhttpsharp/uhttpsharp.csproj index 4ef2c2b..9aaba02 100644 --- a/uhttpsharp/uhttpsharp.csproj +++ b/uhttpsharp/uhttpsharp.csproj @@ -29,6 +29,7 @@ TRACE prompt 4 + bin\Release\uhttpsharp.xml From 34ba717b1f874e5b25f466717ae158b5e5b40a8b Mon Sep 17 00:00:00 2001 From: SandRock Date: Sat, 15 Mar 2014 10:54:59 +0100 Subject: [PATCH 5/5] readme --- README.md | 12 +++++------- uhttpsharp/HttpRequest.cs | 5 +++-- uhttpsharp/HttpRouter.cs | 3 ++- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 44849fb..1ce9b49 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,19 @@ # uhttpsharp +A very lightweight & simple embedded http server for c# + ## In this branch -A few changes I'm making for another project: +A few changes I'm making for [another project](https://github.com/sandrock/MarkDownBrowser/): * Allow multiple instances (on multiple TCP/IP ports) -* Allow bit of IoC -* Use lambdas to define routes + * Bye bye static stuff +* Allow bit of IoC * Convert the HttpHandler class to a IHttpHandler interface * Create a HttpContext class to simplify IHttpHandler -__Source code is not usable at this time (compile errors).__ - ## License -A very lightweight & simple embedded http server for c# - Copyright (C) 2011 uhttpsharp project This library is free software; you can redistribute it and/or diff --git a/uhttpsharp/HttpRequest.cs b/uhttpsharp/HttpRequest.cs index cf6a16a..20491e2 100644 --- a/uhttpsharp/HttpRequest.cs +++ b/uhttpsharp/HttpRequest.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Diagnostics; namespace uhttpsharp { @@ -53,7 +54,7 @@ internal void Process(HttpContext context) if (tokens.Length != 3) { - Console.WriteLine("httpserver: invalid http request."); + Trace.TraceError("httpserver: invalid http request."); return; } @@ -72,7 +73,7 @@ internal void Process(HttpContext context) Uri = new Uri("http://" + context.Server.Address + "/" + URL.TrimStart('/')); Parameters = new HttpRequestParameters(URL); - Console.WriteLine(string.Format("[{0}:{1}] URL: {2}", HttpProtocol, HttpMethod, URL)); + Trace.TraceInformation(string.Format("[{0}:{1}] URL: {2}", HttpProtocol, HttpMethod, URL)); // get the headers string line; diff --git a/uhttpsharp/HttpRouter.cs b/uhttpsharp/HttpRouter.cs index 0721d05..a9710b7 100644 --- a/uhttpsharp/HttpRouter.cs +++ b/uhttpsharp/HttpRouter.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Diagnostics; namespace uhttpsharp { @@ -84,7 +85,7 @@ private void RegisterHandlers() } catch (Exception ex) { - Console.WriteLine(string.Format("Exception during activating the IHttpRequestHandler: {0} - {1}", type, ex)); + Trace.TraceError(string.Format("Exception during activating the IHttpRequestHandler: {0} - {1}", type, ex)); } } }