From bc5aa24bf4d6c34e60f657599c003543b9690fea Mon Sep 17 00:00:00 2001 From: DMP9 Date: Sat, 20 May 2017 12:00:17 +0100 Subject: [PATCH 1/3] Use regex for request line parsing --- .../HttpListenerRequest.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/System.Net.Http.HttpListener/HttpListenerRequest.cs b/src/System.Net.Http.HttpListener/HttpListenerRequest.cs index 8220d32..2797b3f 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,14 @@ 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]; - - Version = line[2]; + var line = lines.ElementAt(0); + Regex regex = new Regex(requestRegex); + Match m = regex.Match(line); + + var url = new UriBuilder(Headers.Host + regex.Groups["url"]).Uri; + var httpMethod = regex.Groups["method"]; + + Version = regex.Groups["version"]; Method = httpMethod; RequestUri = url; } @@ -149,4 +149,4 @@ public async Task ReadContentAsStringAsync() return Encoding.UTF8.GetString(buffer); } } -} \ No newline at end of file +} From 5b6bb51660dad76b77ffab46ed85122427bd7e30 Mon Sep 17 00:00:00 2001 From: DMP9 Date: Sat, 20 May 2017 12:59:03 +0100 Subject: [PATCH 2/3] Fix errors & throw exception if match is unsuccessful --- .../HttpListenerRequest.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/System.Net.Http.HttpListener/HttpListenerRequest.cs b/src/System.Net.Http.HttpListener/HttpListenerRequest.cs index 2797b3f..34ecef7 100644 --- a/src/System.Net.Http.HttpListener/HttpListenerRequest.cs +++ b/src/System.Net.Http.HttpListener/HttpListenerRequest.cs @@ -12,7 +12,7 @@ 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 static string requestRegex = @"^(?GET|HEAD|POST|PUT|DELETE|OPTIONS|TRACE|PATCH).(?.*).(?(HTTP\/1\.1|HTTP\/1\.0))$"; internal HttpListenerRequest(TcpClientAdapter client) { @@ -47,10 +47,15 @@ private void ParseRequestLine(string[] lines) Regex regex = new Regex(requestRegex); Match m = regex.Match(line); - var url = new UriBuilder(Headers.Host + regex.Groups["url"]).Uri; - var httpMethod = regex.Groups["method"]; + 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 = regex.Groups["version"]; + Version = m.Groups["version"]; Method = httpMethod; RequestUri = url; } From de9f069ad5ea76115dfcbb749ac7c3e277ca237a Mon Sep 17 00:00:00 2001 From: Dylan Perks Date: Tue, 5 Feb 2019 20:45:44 +0000 Subject: [PATCH 3/3] Update README.md --- README.md | 99 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 97 deletions(-) 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.