diff --git a/README.md b/README.md index 346a87b..2d9a6df 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,2 @@ -# HttpListener for .NET Core and UWP - -A simple library that essentially allows for building your own HTTP server on .NET Core and the Universal Windows Platform (UWP). - -## Overview - -This library fills the void left by the missing System.Net.Http.HttpListener in .NET Core and Universal Windows Platform (UWP). - -By targetting .NET Core and UWP, this API enables HTTP server scenarios on Windows 10 for IoT on Raspberry Pi (2 & 3). - -Taking a modern approach, this API is not meant to be entirely compatible with the HttpListener found in the full .NET Framework on Windows desktop. - -Please, be aware that this is an early concept, and thus not ready for production. - -Contributions are most welcome. - -## Solution - -The solution consists of two projects with a common core targetting: - -1. .NET Core project - Windows, Linux and Mac OS X. -2. Universal Windows Platform (UWP) - Windows 10 and up. - -The API:s are generally similar, but may differ slightly on each platform due to their respective API constraints. However, the core concepts remain the same. - -On .NET Core it uses .NET:s TcpListener and TcpClient. - -On UWP it uses Windows Runtime's StreamSocketListener and StreamSocket. - -## Get the package(s) - -The latest version that has been release can be found in this NuGet feed: - -``` -https://www.myget.org/F/roberts-core-feed/api/v3/index.json -``` - -Add this to your Package Sources. - -Search for "HttpListener" and the packages "System.Net.Http.HttpListener" and "System.Net.Http.HttpListener.UWP" should show up. - -Choose the one that is to your liking. - -## Todo - -Here are some things to consider doing in the future: - -* Rewrite the HttpRequest parser and implement missing features, like authentication and the handling of content types. -* Consolidate the two libraries (.NET Core and UWP) into one single .NET Standard-compliant library when possible to do so. - -## Sample - -Add the using statement. - -```CSharp -... -using System.Net.Http; -``` - -The code used in this sample should be the same on any platform. - -```CSharp -var listener = new HttpListener(IPAddress.Parse("127.0.0.1"), 8081); -try -{ - listener.Request += async (sender, context) => { - var request = context.Request; - var response = context.Response; - if(request.Method == HttpMethod.Get) - { - await response.WriteAsync($"Hello from Server at: {DateTime.Now}\r\n"); - } - else - { - response.MethodNotAllowed(); - } - // Close the HttpResponse to send it back to the client. - response.Close(); - }; - listener.Start(); - - Console.WriteLine("Press any key to exit."); - Console.ReadKey(); -} -catch(Exception exc) -{ - Console.WriteLine(exc.ToString()); -} -finally -{ - listener.Close(); -} -``` - -Visit 127.0.0.1:8081 in your browser. - -Also consider having a look at the unit tests. +# Obsolete +Use [SimpleServer](https://github.com/Ultz/SimpleServer) instead. diff --git a/src/System.Net.Http.HttpListener/HttpListenerRequest.cs b/src/System.Net.Http.HttpListener/HttpListenerRequest.cs index 8220d32..34ecef7 100644 --- a/src/System.Net.Http.HttpListener/HttpListenerRequest.cs +++ b/src/System.Net.Http.HttpListener/HttpListenerRequest.cs @@ -1,14 +1,18 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Text.RegularExpressions; namespace System.Net.Http { public sealed class HttpListenerRequest { private TcpClientAdapter client; + + // Request regex developed by DMP9 Labs + internal static string requestRegex = @"^(?GET|HEAD|POST|PUT|DELETE|OPTIONS|TRACE|PATCH).(?.*).(?(HTTP\/1\.1|HTTP\/1\.0))$"; internal HttpListenerRequest(TcpClientAdapter client) { @@ -26,12 +30,6 @@ internal async Task ProcessAsync() var localEndpoint = client.LocalEndPoint; var remoteEnpoint = client.RemoteEndPoint; - // This code needs to be rewritten and simplified. - - var requestLines = request.ToString().Split('\n'); - string requestMethod = requestLines[0].TrimEnd('\r'); - string[] requestParts = requestMethod.Split(' '); - LocalEndpoint = (IPEndPoint)localEndpoint; RemoteEndpoint = (IPEndPoint)remoteEnpoint; @@ -45,12 +43,19 @@ internal async Task ProcessAsync() private void ParseRequestLine(string[] lines) { - var line = lines.ElementAt(0).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - - var url = new UriBuilder(Headers.Host + line[1]).Uri; - var httpMethod = line[0]; + var line = lines.ElementAt(0); + Regex regex = new Regex(requestRegex); + Match m = regex.Match(line); + + if (!m.Successful) + { + throw new Exception("Invalid request -- couldn't match request line to regex"); + } + + var url = new UriBuilder(Headers.Host + m.Groups["url"]).Uri; + var httpMethod = m.Groups["method"]; - Version = line[2]; + Version = m.Groups["version"]; Method = httpMethod; RequestUri = url; } @@ -149,4 +154,4 @@ public async Task ReadContentAsStringAsync() return Encoding.UTF8.GetString(buffer); } } -} \ No newline at end of file +}