From 8012f01dde2df5445032047978cedbab0d9d57af Mon Sep 17 00:00:00 2001 From: Harald Wolff-Thobaben Date: Wed, 15 Dec 2021 10:56:33 +0100 Subject: [PATCH] Reimplementation through ln.protocols.helper and code cleanup --- .idea/.idea.ln.http/.idea/.gitignore | 13 + build.ln | 2 +- ln.http.service/Program.cs | 22 + ln.http.service/ln.http.service.csproj | 13 + ln.http.sln | 28 + ln.http.tests/UnitTest1.cs | 36 ++ ln.http.tests/ln.http.tests.csproj | 13 +- ln.http/AuthenticationProvider.cs | 38 -- ln.http/AuthorizationMask.cs | 22 - ln.http/HTTPServer.cs | 181 +++--- ln.http/HTTPServerConnection.cs | 157 ----- ln.http/HttpHeader.cs | 31 - ln.http/HttpHeaders.cs | 36 -- ln.http/HttpMethod.cs | 2 +- ln.http/HttpReader.cs | 320 ----------- ln.http/HttpRequest.cs | 299 +++------- ln.http/HttpResponse.cs | 25 +- ln.http/HttpRouter.cs | 36 -- ln.http/HttpUser.cs | 30 - ln.http/IHTTPResource.cs | 8 - ln.http/client/HttpClientRequest.cs | 4 +- ln.http/connections/Connection.cs | 6 +- ln.http/connections/HttpsConnection.cs | 2 +- ln.http/exceptions/HttpException.cs | 2 + ln.http/listener/HttpListener.cs | 2 + ln.http/listener/Listener.cs | 2 +- ln.http/ln.http.csproj | 11 +- ln.http/message/Header.cs | 159 ----- ln.http/message/HeaderContainer.cs | 76 --- ln.http/message/Message.cs | 153 ----- ln.http/message/MimeTypeMap.cs | 767 ------------------------- ln.http/message/TokenReader.cs | 68 --- ln.http/message/parser/HTTP.cs | 40 -- ln.http/message/parser/MIME.cs | 43 -- ln.http/router/FileRouter.cs | 4 +- ln.http/router/HttpRoutingContext.cs | 3 +- ln.http/router/LoggingRouter.cs | 4 +- ln.http/router/RouterTarget.cs | 14 +- ln.http/router/StaticRouter.cs | 5 +- ln.http/router/VirtualHostRouter.cs | 24 +- ln.http/session/Session.cs | 4 +- ln.http/session/SessionCache.cs | 10 +- ln.http/websocket/WebSocket.cs | 7 +- ln.http/websocket/WebSocketResponse.cs | 7 +- 44 files changed, 376 insertions(+), 2353 deletions(-) create mode 100644 .idea/.idea.ln.http/.idea/.gitignore create mode 100644 ln.http.service/Program.cs create mode 100644 ln.http.service/ln.http.service.csproj delete mode 100644 ln.http/AuthenticationProvider.cs delete mode 100644 ln.http/AuthorizationMask.cs delete mode 100644 ln.http/HTTPServerConnection.cs delete mode 100644 ln.http/HttpHeader.cs delete mode 100644 ln.http/HttpHeaders.cs delete mode 100644 ln.http/HttpReader.cs delete mode 100644 ln.http/HttpRouter.cs delete mode 100644 ln.http/HttpUser.cs delete mode 100644 ln.http/IHTTPResource.cs delete mode 100644 ln.http/message/Header.cs delete mode 100644 ln.http/message/HeaderContainer.cs delete mode 100644 ln.http/message/Message.cs delete mode 100644 ln.http/message/MimeTypeMap.cs delete mode 100644 ln.http/message/TokenReader.cs delete mode 100644 ln.http/message/parser/HTTP.cs delete mode 100644 ln.http/message/parser/MIME.cs diff --git a/.idea/.idea.ln.http/.idea/.gitignore b/.idea/.idea.ln.http/.idea/.gitignore new file mode 100644 index 0000000..2da445b --- /dev/null +++ b/.idea/.idea.ln.http/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.ln.http.iml +/contentModel.xml +/modules.xml +/projectSettingsUpdater.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/build.ln b/build.ln index afa2528..2a0641a 100644 --- a/build.ln +++ b/build.ln @@ -3,7 +3,7 @@ "dotnet" ], "env": { - "NUGET_SOURCE": "https://nexus.niclas-thobaben.de/repository/l--n.de/", + "NUGET_SOURCE": "https://nexus.l--n.de/repository/ln.net/", "CONFIGURATION": "Release" }, "stages": [ diff --git a/ln.http.service/Program.cs b/ln.http.service/Program.cs new file mode 100644 index 0000000..ef18911 --- /dev/null +++ b/ln.http.service/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using ln.http; +using ln.http.listener; +using ln.http.router; + +namespace ln.http.service +{ + class Program + { + static void Main(string[] args) + { + StaticRouter staticRouter = new StaticRouter("."); + HTTPServer httpServer = new HTTPServer(new HttpListener(8888), new LoggingRouter(staticRouter)); + + httpServer.Start(); + + lock (httpServer) + Monitor.Wait(httpServer); + } + } +} diff --git a/ln.http.service/ln.http.service.csproj b/ln.http.service/ln.http.service.csproj new file mode 100644 index 0000000..602adda --- /dev/null +++ b/ln.http.service/ln.http.service.csproj @@ -0,0 +1,13 @@ + + + + Exe + net5.0 + 9 + + + + + + + diff --git a/ln.http.sln b/ln.http.sln index df37118..63f9281 100644 --- a/ln.http.sln +++ b/ln.http.sln @@ -7,6 +7,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.http", "ln.http\ln.http. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.http.tests", "ln.http.tests\ln.http.tests.csproj", "{476CD242-9329-449C-95E4-A5317635B223}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.http.service", "ln.http.service\ln.http.service.csproj", "{FE139A5A-A388-4656-AD15-149012EDB9D0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.protocols.helper", "..\ln.protocols.helper\ln.protocols.helper.csproj", "{1C1D3A17-A615-4686-90BD-F0E221EAC89C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,5 +48,29 @@ Global {476CD242-9329-449C-95E4-A5317635B223}.Release|x64.Build.0 = Release|Any CPU {476CD242-9329-449C-95E4-A5317635B223}.Release|x86.ActiveCfg = Release|Any CPU {476CD242-9329-449C-95E4-A5317635B223}.Release|x86.Build.0 = Release|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Debug|x64.Build.0 = Debug|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Debug|x86.ActiveCfg = Debug|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Debug|x86.Build.0 = Debug|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Release|Any CPU.Build.0 = Release|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Release|x64.ActiveCfg = Release|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Release|x64.Build.0 = Release|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Release|x86.ActiveCfg = Release|Any CPU + {FE139A5A-A388-4656-AD15-149012EDB9D0}.Release|x86.Build.0 = Release|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Debug|x64.ActiveCfg = Debug|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Debug|x64.Build.0 = Debug|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Debug|x86.ActiveCfg = Debug|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Debug|x86.Build.0 = Debug|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|Any CPU.Build.0 = Release|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x64.ActiveCfg = Release|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x64.Build.0 = Release|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x86.ActiveCfg = Release|Any CPU + {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/ln.http.tests/UnitTest1.cs b/ln.http.tests/UnitTest1.cs index 32f6467..4349f07 100644 --- a/ln.http.tests/UnitTest1.cs +++ b/ln.http.tests/UnitTest1.cs @@ -1,17 +1,53 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using ln.http.router; +using ln.type; using NUnit.Framework; namespace ln.http.tests { public class Tests { + HTTPServer server; + int testPort; + [SetUp] public void Setup() { + if (server != null) + return; + + SimpleRouter testRouter = new SimpleRouter(); + + StaticRouter staticRouter = new StaticRouter(AppContext.BaseDirectory); + testRouter.AddSimpleRoute("/static/*", staticRouter); + + server = new HTTPServer(testRouter); + server.AddEndpoint(new Endpoint(IPv6.ANY,0)); + + server.Start(); + + testPort = server.Listeners[0].LocalEndpoint.Port; + TestContext.Error.WriteLine("Using Port {0}", testPort); } [Test] public void Test1() { + HttpClient client = new HttpClient(); + HttpResponseMessage response = client.GetAsync(String.Format("http://localhost:{0}/static/test.txt", testPort)).Result; + + Assert.AreEqual(System.Net.HttpStatusCode.OK, response.StatusCode); + + byte[] contentBytes = response.Content.ReadAsByteArrayAsync().Result; + byte[] fileBytes = File.ReadAllBytes("test.txt"); + + CollectionAssert.AreEqual(fileBytes, contentBytes); + + //server.Stop(); + Assert.Pass(); } } diff --git a/ln.http.tests/ln.http.tests.csproj b/ln.http.tests/ln.http.tests.csproj index bb8d64c..066f518 100644 --- a/ln.http.tests/ln.http.tests.csproj +++ b/ln.http.tests/ln.http.tests.csproj @@ -1,15 +1,24 @@ - netcoreapp3.1 + net5.0 false + + 9 - + + + + + + + Always + diff --git a/ln.http/AuthenticationProvider.cs b/ln.http/AuthenticationProvider.cs deleted file mode 100644 index f9922dc..0000000 --- a/ln.http/AuthenticationProvider.cs +++ /dev/null @@ -1,38 +0,0 @@ -// /** -// * File: AuthenticationProvider.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.Collections.Generic; -namespace ln.http -{ - public abstract class AuthenticationProvider - { - public AuthenticationProvider() - { - } - - public abstract IEnumerable EnumerateUsers(); - public abstract HttpUser Authenticate(HttpRequest httpRequest); - - public virtual HttpUser GetHttpUser(String authenticationName) - { - foreach (HttpUser httpUser in EnumerateUsers()) - { - if (httpUser.AuthenticationName.Equals(authenticationName)) - { - return httpUser; - } - } - throw new KeyNotFoundException(); - } - - - - } -} diff --git a/ln.http/AuthorizationMask.cs b/ln.http/AuthorizationMask.cs deleted file mode 100644 index d77d21f..0000000 --- a/ln.http/AuthorizationMask.cs +++ /dev/null @@ -1,22 +0,0 @@ -// /** -// * File: AuthorizationMask.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -namespace ln.http -{ - public static class AuthorizationMask - { - public static readonly long A_ACCESS = (1l << 0); - public static readonly long A_READ = (1l << 0); - public static readonly long A_WRITE = (1l << 0); - public static readonly long A_EXEC = (1l << 0); - - public static readonly long A_SUPER = (-1); - } -} diff --git a/ln.http/HTTPServer.cs b/ln.http/HTTPServer.cs index 4517765..dab3120 100644 --- a/ln.http/HTTPServer.cs +++ b/ln.http/HTTPServer.cs @@ -5,7 +5,6 @@ using ln.threading; using ln.application; using ln.http.listener; using ln.http.connections; -using System.Globalization; using ln.http.exceptions; using System.Threading; using ln.type; @@ -22,7 +21,7 @@ namespace ln.http public IHttpRouter Router { get; set; } - public bool IsRunning => !shutdown && (threadPool.CurrentPoolSize > 0); + public bool IsRunning => !shutdown; public Logger Logger { get; set; } bool shutdown = false; @@ -30,16 +29,12 @@ namespace ln.http List listeners = new List(); public Listener[] Listeners => listeners.ToArray(); - DynamicPool threadPool; - public DynamicPool ThreadPool => threadPool; - HashSet currentConnections = new HashSet(); public IEnumerable CurrentConnections => currentConnections; public HTTPServer() { Logger = Logger.Default; - threadPool = new DynamicPool(1024); } public HTTPServer(IHttpRouter router) : this() @@ -63,14 +58,14 @@ namespace ln.http public void StartListener(Listener listener) { + if (listener.IsOpen) + return; + listener.Open(); - threadPool.Enqueue( + DynamicThreadPool.DefaultPool.Enqueue( () => listener.AcceptMany( - (connection) => threadPool.Enqueue( - () => this.HandleConnection(connection) - ) - ) + (connection) => this.HandleConnection(connection)) ); } @@ -87,10 +82,8 @@ namespace ln.http public void Start() { - threadPool.Start(); - foreach (Listener listener in listeners) - StartListener(listener); + if (!listener.IsOpen) StartListener(listener); } public void Stop() @@ -123,101 +116,97 @@ namespace ln.http connection.Close(); } } - - threadPool.Stop(true); } - private void HandleConnection(Connection connection) + private void HandleConnection(Connection connection, bool dontClose = false) { lock (this.currentConnections) currentConnections.Add(connection); - try + bool keepalive = false; + + do { - HttpRequest httpRequest = null; - bool keepAlive = true; - try + using (HttpRequest httpRequest = connection.ReadRequest(this)) { - do + HttpResponse httpResponse = null; + + if (httpRequest == null) + break; + + try { - httpRequest = connection.ReadRequest(this); + httpResponse = Router.Route(new HttpRoutingContext(httpRequest), httpRequest); + if (httpResponse == null) + httpResponse = HttpResponse.NotFound(); + } + catch (Exception exception) + { + Logging.Log(exception); + if ((exception is HttpException httpException) && (httpException.HttpResponse != null)) + httpResponse = httpException.HttpResponse; + else + httpResponse = HttpResponse.InternalServerError() + .Content(String.Format("An internal error occured ({0})", exception.ToString())); + } - if (httpRequest == null) - break; + httpResponse.WriteTo(connection.GetStream()); + httpResponse?.ContentStream?.Dispose(); - HttpResponse response; - try - { - response = Router.Route(new HttpRoutingContext(httpRequest),httpRequest); - } - catch (HttpException httpExc) - { - response = new HttpResponse((HttpStatusCode)httpExc.StatusCode).Content(httpExc.Message); - } - - if (response == null) - response = HttpResponse.NotFound().Content(String.Format("The URI {0} could not be found on this server.", httpRequest.URI)); - - keepAlive = httpRequest.GetRequestHeader("connection", "keep-alive").Equals("keep-alive") && response.GetHeader("connection", "keep-alive").Equals("keep-alive"); - response.SetHeader("connection", keepAlive ? "keep-alive" : "close"); - - SendResponse(connection.GetStream(), httpRequest, response); - - response?.ContentStream?.Dispose(); - - } while (keepAlive); + keepalive = httpResponse.GetHeader("connection", "keep-alive").Equals("keep-alive") && httpRequest + .GetRequestHeader("connection", + httpRequest.Protocol.Equals("HTTP/1.1") ? "keep-alive" : "close").Contains("keep-alive", + StringComparison.InvariantCultureIgnoreCase); } - catch (Exception e) - { - Logging.Log(e); - HttpResponse - .InternalServerError() - .Content(e) - .SendResponse(connection.GetStream(), httpRequest); - } - - HttpRequest.ClearCurrent(); - connection.Close(); - } finally - { - lock (currentConnections) - currentConnections.Remove(connection); - } + } while (keepalive); + + lock (this.currentConnections) + currentConnections.Remove(connection); + connection.Close(); + + // new threading.Promise((resolve, reject)=>{ + // resolve(connection.ReadRequest(this)); + // }) + // .Then((httpRequest)=> + // { + // if (httpRequest == null) + // return null; + // return Router.Route(new HttpRoutingContext(httpRequest),httpRequest); + // }) + // // .Then((httpResponse)=>{ + // // if (httpResponse == null) + // // throw new Exception("no response returned"); + // // return httpResponse; + // // }) + // .Catch((exception)=>{ + // Logging.Log(exception); + // if ((exception is HttpException httpException) && (httpException.HttpResponse != null)) + // return httpException.HttpResponse; + // return HttpResponse + // .InternalServerError() + // .Content(String.Format("An internal error occured ({0})", exception.ToString())); + // }) + // .Then((httpResponse)=> + // { + // if (httpResponse == null) + // return false; + // + // httpResponse.SendResponse(connection.GetStream()); + // httpResponse?.ContentStream?.Dispose(); + // return httpResponse.GetHeader("connection", "keep-alive").Equals("keep-alive"); + // }) + // .Then((keepalive)=>{ + // if (keepalive) + // HandleConnection(connection, true); + // }) + // .Finally(()=>{ + // lock (this.currentConnections) + // currentConnections.Remove(connection); + // connection.Close(); + // }) + // ; } - - public static void SendResponse(Stream stream, HttpRequest request, HttpResponse response) - { - response.SendResponse(stream, request); -/* - request.FinishRequest(); - response.SetHeader("Content-Length", response.ContentStream.Length.ToString()); - - StreamWriter streamWriter = new StreamWriter(stream); - streamWriter.NewLine = "\r\n"; - - streamWriter.WriteLine("{0} {1} {2}", request.Protocol, (int)response.HttpStatusCode, response.HttpStatusCode.ToString()); - foreach (String headerName in response.GetHeaderNames()) - { - streamWriter.WriteLine("{0}: {1}", headerName, response.GetHeader(headerName)); - } - - foreach (HttpCookie httpCookie in response.Cookies) - { - streamWriter.WriteLine("Set-Cookie: {0}", httpCookie.ToString()); - } - - streamWriter.WriteLine(); - streamWriter.Flush(); - - response.ContentStream.Position = 0; - response.ContentStream.CopyTo(stream); - response.ContentStream.Close(); - response.ContentStream.Dispose(); - - stream.Flush(); - */ - } - + public static void StartSimpleServer(string[] arguments) { ArgumentContainer argumentContainer = new ArgumentContainer(new Argument[] diff --git a/ln.http/HTTPServerConnection.cs b/ln.http/HTTPServerConnection.cs deleted file mode 100644 index b99a875..0000000 --- a/ln.http/HTTPServerConnection.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Net.Sockets; -using ln.threading; -using System.Net; -using ln.type; -using ln.logging; -using System.IO; -using System.Threading; -using System.Collections.Generic; -using System.Linq; -namespace ln.http -{ - //public delegate void HTTPServerConnectionEvent(HTTPServerConnection connection); - - //public class HTTPServerConnection : PoolJob - //{ - // public static ThreadLocal Current { get; } = new ThreadLocal(); - // static HashSet currentConnections = new HashSet(); - // public static HTTPServerConnection[] CurrentConnections => currentConnections.ToArray(); - - // public HTTPServer HTTPServer { get; } - // public TcpClient TcpClient { get; } - - // public HttpRequest CurrentRequest { get; protected set; } - - // public event HTTPServerConnectionEvent AbortRequested; - - // public DateTime Created { get; } - // public DateTime Interpreted { get; set; } - // public DateTime Finished { get; set; } - - // public HTTPServerConnection(HTTPServer httpServer,TcpClient tcpClient) - // { - // HTTPServer = httpServer; - // TcpClient = tcpClient; - // Created = DateTime.Now; - // } - - // public virtual HttpResponse GetResponse(HttpRequest httpRequest,HttpApplication httpApplication) => httpApplication.GetResponse(httpRequest); - - // public virtual void Abort() - // { - // if (AbortRequested != null) - // AbortRequested(this); - // } - - - // public override void RunJob() - // { - // HTTPServerConnection saveCurrent = Current.Value; - // Current.Value = this; - // lock (currentConnections) - // currentConnections.Add(this); - - // try - // { - // setState("reading http request"); - - // HttpReader httpReader = new HttpReader(TcpClient.GetStream()); - // httpReader.Read(); - - // if (!httpReader.Valid) - // return; - - // HttpResponse response = null; - - // using (CurrentRequest = new HttpRequest(this.HTTPServer,httpReader, (IPEndPoint)TcpClient.Client.LocalEndPoint)) - // { - // Interpreted = DateTime.Now; - - // try - // { - // HttpApplication application = HTTPServer.GetHttpApplication(new URI(CurrentRequest.BaseURI.ToString())); - - // application.Authenticate(CurrentRequest); - // application.Authorize(CurrentRequest); - - // setState("handling http request"); - - // response = GetResponse(CurrentRequest, application); - // } - // catch (Exception e) - // { - // setState("handling exception"); - - // response = new HttpResponse(CurrentRequest, "text/plain"); - // response.StatusCode = 500; - // response.ContentWriter.WriteLine("Exception caught: {0}", e); - // } - - // setState("sending response"); - - // if (response == null) - // { - // Logging.Log(LogLevel.DEBUG, "Request {0} returned no Response", CurrentRequest); - // } - // else - // { - // if (!response.HasCustomContentStream) - // { - // response.ContentWriter.Flush(); - // MemoryStream cstream = (MemoryStream)response.ContentStream; - // cstream.Position = 0; - - // response.SetHeader("content-length", cstream.Length.ToString()); - // } - - // if (CurrentRequest.Session != null) - // HTTPServer?.SessionCache?.ApplySessionID(response, CurrentRequest.Session); - - // response.AddCookie("LN_SEEN", DateTime.Now.ToString()); - - // SendResponse(TcpClient.GetStream(), response); - // TcpClient.Close(); - - // Finished = DateTime.Now; - - // HTTPServer.Log(Created, (Finished - Created).TotalMilliseconds, CurrentRequest, response); - // } - // } - // } - // finally - // { - // Current.Value = saveCurrent; - // lock (currentConnections) - // currentConnections.Remove(this); - // } - // } - - // public static void SendResponse(Stream stream, HttpResponse response) - // { - // StreamWriter streamWriter = new StreamWriter(stream); - // streamWriter.NewLine = "\r\n"; - - // streamWriter.WriteLine("{0} {1} {2}", response.HttpRequest.Protocol, response.StatusCode, response.StatusMessage); - // foreach (String headerName in response.GetHeaderNames()) - // { - // streamWriter.WriteLine("{0}: {1}", headerName, response.GetHeader(headerName)); - // } - - // foreach (HttpCookie httpCookie in response.Cookies) - // { - // streamWriter.WriteLine("Set-Cookie: {0}", httpCookie.ToString()); - // } - - // streamWriter.WriteLine(); - // streamWriter.Flush(); - - // response.ContentStream.CopyTo(stream); - // response.ContentStream.Close(); - // response.ContentStream.Dispose(); - - // streamWriter.Flush(); - // } - - //} -} diff --git a/ln.http/HttpHeader.cs b/ln.http/HttpHeader.cs deleted file mode 100644 index 2779d32..0000000 --- a/ln.http/HttpHeader.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -namespace ln.http -{ - public class HttpHeader - { - public String Name { get; } - public String Value { get; } - - public HttpHeader(String rawHeader) - { - int colon = rawHeader.IndexOf(':'); - if (colon < 0) - throw new FormatException("rawHeader must contain at least one colon"); - - Name = rawHeader.Substring(0, colon).Trim().ToUpper(); - Value = rawHeader.Substring(colon + 1).Trim(); - } - - public HttpHeader(String headerName,String headerValue) - { - if (String.Empty.Equals(headerName)) - throw new ArgumentException("headerName needs to contain at least one character", nameof(headerName)); - - Name = headerName.ToUpper(); - Value = headerValue.ToUpper(); - } - - - - } -} diff --git a/ln.http/HttpHeaders.cs b/ln.http/HttpHeaders.cs deleted file mode 100644 index 16c6f9f..0000000 --- a/ln.http/HttpHeaders.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using ln.collections; -using System.Collections.Generic; -using System.Collections; - -namespace ln.http -{ - public class HttpHeaders : IEnumerable - { - MappingBTree headers = new MappingBTree((value) => value.Name); - - public HttpHeaders() - { - } - - public HttpHeader this[string headerName] => headers[headerName.ToUpper()]; - public bool Contains(string headerName) => headers.ContainsKey(headerName.ToUpper()); - - public void Add(String headerName, String headerValue) => Add(new HttpHeader(headerName, headerValue)); - public void Add(HttpHeader httpHeader) => headers.Add(httpHeader); - - public void Remove(HttpHeader httpHeader) => headers.Remove(httpHeader); - public void Remove(string headerName) => headers.RemoveKey(headerName.ToUpper()); - - public void Set(String headerName, String headerValue) - { - if (headers.ContainsKey(headerName)) - Remove(headerName); - - Add(new HttpHeader(headerName, headerValue)); - } - - public IEnumerator GetEnumerator() => headers.Values.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => headers.Values.GetEnumerator(); - } -} diff --git a/ln.http/HttpMethod.cs b/ln.http/HttpMethod.cs index 7dce68d..e5a5c15 100644 --- a/ln.http/HttpMethod.cs +++ b/ln.http/HttpMethod.cs @@ -3,6 +3,6 @@ namespace ln.http { public enum HttpMethod { - HEAD, GET, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS, TRACE + UNKOWN, HEAD, GET, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS, TRACE, PROPFIND, MKCOL, LOCK, UNLOCK } } \ No newline at end of file diff --git a/ln.http/HttpReader.cs b/ln.http/HttpReader.cs deleted file mode 100644 index ce3aab6..0000000 --- a/ln.http/HttpReader.cs +++ /dev/null @@ -1,320 +0,0 @@ -using System; -using System.IO; -using System.Text; -using System.Collections.Generic; -using System.Net; -using ln.type; -using ln.http.message; -using ln.http.io; -using ln.http.message.parser; - -namespace ln.http -{ - //public class HttpReader - //{ - // delegate bool ReadCondition(int b); - - // public Stream Stream { get; } - - // private byte[] buffer = new byte[8192]; - // private int hlen; - // private int blen; - // private int bptr; - - // public Endpoint RemoteEndpoint { get; private set; } - - // public HeaderContainer Headers { get; private set; } - - // public String Method { get; private set; } - // public String URL { get; private set; } - // public String Protocol { get; private set; } - - // //public Dictionary Headers { get; } = new Dictionary(); - - // public bool Valid { get; private set; } = false; - - // public HttpReader(Stream stream) - // { - // Stream = stream; - // } - // public HttpReader(Stream stream,Endpoint remoteEndpoint) - // { - // Stream = stream; - // RemoteEndpoint = remoteEndpoint; - // } - - // public void Read() - // { - // UnbufferedStreamReader reader = new UnbufferedStreamReader(Stream); - // string requestLine = reader.ReadLine(); - // string[] requestTokens = requestLine.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); - - // if (requestTokens.Length != 3) - // throw new FormatException("request line malformed"); - - // Method = requestTokens[0]; - // URL = requestTokens[1]; - // Protocol = requestTokens[2]; - - // Headers = HTTP.ReadHeader(reader); - - // Valid = true; - // } - - // public int ReadByte() - // { - // if (bptr >= blen) - // return -1; - // return buffer[bptr++]; - // } - - // public int Current - // { - // get - // { - // if (bptr >= blen) - // return -1; - // return buffer[bptr]; - // } - // } - - // public void Reverse() - // { - // if ((bptr > 0) && (bptr < blen)) - // bptr--; - // } - - // public void ReadRequestHead() - // { - // bptr = 0; - // do - // { - // int rlen = Stream.Read(buffer, blen, buffer.Length - blen); - // if (rlen == 0) - // throw new IOException(); - - // blen += rlen; - // while (bptr <= (blen - 4)) - // { - // if ( - // (buffer[bptr + 0] == '\r') && - // (buffer[bptr + 1] == '\n') && - // (buffer[bptr + 2] == '\r') && - // (buffer[bptr + 3] == '\n') - // ) - // { - // hlen = bptr; - // bptr = 0; - // return; - // } - // bptr++; - // } - - // byte[] nbuffer = new byte[buffer.Length << 1]; - // Array.Copy(buffer, nbuffer, buffer.Length); - // buffer = nbuffer; - // } while (blen >= buffer.Length); - // bptr = 0; - // } - - // private String ReadConditional(ReadCondition readCondition,bool reverse = true) - // { - // StringBuilder stringBuilder = new StringBuilder(); - // int b = ReadByte(); - // while ((b != -1) && (readCondition(b)) ) - // { - // stringBuilder.Append((char)b); - // b = ReadByte(); - // } - // if (reverse) - // Reverse(); - - // return stringBuilder.ToString(); - // } - - // public void SkipWhiteSpace() - // { - // while (Char.IsWhiteSpace((char)ReadByte())) { }; - // Reverse(); - // } - - // public String ReadToken() - // { - // return ReadConditional((b) => !Char.IsWhiteSpace((char)b)); - // } - - // public String ReadLine() - // { - // int p = bptr; - // while (p < blen - 1) - // { - // if ((buffer[p] == '\r') && (buffer[p + 1] == '\n')) - // { - // break; - // } - // p++; - // } - - // string result = Encoding.ASCII.GetString(buffer, bptr, p - bptr); - // bptr = p + 2; - // return result; - // } - - // public String ReadHeaderName() - // { - // return ReadConditional((b) => b != ':', false).ToUpper(); - // } - // public String ReadHeaderValue() - // { - // String value = ReadLine(); - // while (Char.IsWhiteSpace((char)Current)) - // { - // value = value + ReadLine(); - // } - // return value.Trim(); - // } - - // //public void ReadHeaders() - // //{ - // // while (bptr < hlen) - // // { - // // String name = ReadHeaderName(); - // // String value = ReadHeaderValue(); - - // // Headers.Add(name, value); - // // } - // //} - - // public int ReadRequestBody(byte[] dst,int offset,int length) - // { - // //int nRead = 0; - // //if (bptr < blen) - // //{ - // // int len = Math.Min(length, blen - bptr); - // // Array.Copy(buffer, bptr, dst, offset, len); - // // bptr += len; - // // length -= len; - // // offset += len; - // // nRead += len; - // //} - // int nRead = 0; - // while (length > 0) - // { - // int nr = Stream.Read(dst, offset, length); - // if (nr > 0) - // { - // nRead += nr; - // length -= nr; - // offset += nr; - // } - // } - // return nRead; - // } - - - - // /* - // byte[] buffer; - // int blen = 0; - // int bptr = 0; - - // public HttpReader(Stream stream) - // { - // Stream = stream; - // buffer = new byte[1024]; - // } - // public HttpReader(Stream stream, int buffersize) - // { - // Stream = stream; - // buffer = new byte[buffersize]; - // } - - // private int read() - // { - // if (bptr >= blen) - // { - // bptr = 0; - // blen = Stream.Read(buffer, 0, buffer.Length); - // if (blen <= 0) - // throw new EndOfStreamException(); - // } - // return buffer[bptr++]; - // } - - // private int ReadTo(byte[] b,int offset,byte[] mark) - // { - // int pm = 0; - // int p = offset; - // while (p < b.Length) - // { - // b[p] = (byte)read(); - // if (b[p] == mark[pm]) - // { - // pm++; - // if (pm >= mark.Length) - // { - // p++; - // break; - // } - // } - // else - // { - // pm = 0; - // } - // p++; - // } - // return p; - // } - - - // public String ReadRequestLine(int maxSize = 1024) - // { - // byte[] b = new byte[maxSize]; - // int l = ReadTo(b, 0, new byte[] { 0x0d, 0x0a }); - // return Encoding.ASCII.GetString(b, 0, l); - // } - - // public Dictionary ReadHTTPHeaders() - // { - // byte[] b = new byte[8192]; - // int hlen = ReadTo(b, 0, new byte[] { 0x0d, 0x0a, 0x0d, 0x0a }); - - // Dictionary headers = new Dictionary(); - - // string rawHeaders = Encoding.ASCII.GetString(b, 0, hlen); - // String[] rawLines = rawHeaders.Split(new String[] { "\r\n" }, StringSplitOptions.None); - - // for (int n = rawLines.Length-1; n >= 0 ; n--) - // { - // if ((rawLines[n].Length > 0) && (Char.IsWhiteSpace(rawLines[n][0]))) - // { - // rawLines[n - 1] = rawLines[n - 1] + rawLines[n]; - // rawLines[n] = null; - // } - // } - - // foreach (String rawLine in rawLines) - // { - // if (rawLine != null) - // { - // int colon = rawLine.IndexOf(':'); - // if (colon > 0) - // { - // String name = rawLine.Substring(0, colon).Trim().ToUpper(); - // String value = rawLine.Substring(colon + 1).Trim(); - // headers.Add(name, value); - // } - // } - // } - - // return headers; - // } - - // public byte[] ReadRequestBody(byte[] buffer) - // { - // return null; - // } - // */ - //} - -} diff --git a/ln.http/HttpRequest.cs b/ln.http/HttpRequest.cs index 3a8cb08..a3e9acc 100644 --- a/ln.http/HttpRequest.cs +++ b/ln.http/HttpRequest.cs @@ -2,195 +2,83 @@ using System.IO; using System.Collections.Generic; using System.Linq; -using ln.type; -using ln.http.exceptions; -using System.Threading; -using ln.http.session; -using ln.http.message; -using ln.http.io; -using ln.http.message.parser; +using System.Net; +using ln.protocols.helper; +using ln.rtp; namespace ln.http -{ - public class HttpRequest : IDisposable - { - static ThreadLocal current = new ThreadLocal(); - static public HttpRequest Current => current.Value; +{ public class HttpRequest : IDisposable + { + public Request BaseRequest { get; } + public HTTPServer Server { get; } + + public String Protocol => BaseRequest.Protocol; + public HttpMethod Method { get; } + + public IPAddress ClientAddress { get; } + public String Host { get; } + public int Port { get; } + public bool TLS { get; } + + public HeaderContainer Headers => BaseRequest.Headers; + public QueryStringParameters Query { get; private set; } + + public Stream ContentStream => BaseRequest.ContentStream; + public Stream ConnectionStream => BaseRequest.ContentStream.BaseStream; + + public Uri BaseUri { get; } + public Uri RequestUri { get; } + - //Dictionary requestHeaders; - HeaderContainer requestHeaders; Dictionary requestCookies; Dictionary requestParameters; - public HTTPServer HTTPServer { get; } - public Endpoint RemoteEndpoint { get; private set; } - public Endpoint LocalEndpoint { get; private set; } - - public Uri BaseURI { get; set; } - public Uri URI { get; private set; } - - [Obsolete] - public String Method { get => HttpMethod.ToString(); private set => throw new NotImplementedException(); } - public HttpMethod HttpMethod { get; private set; } - public String RequestURL { get; private set; } - public String Protocol { get; private set; } - - public String Hostname { get; private set; } - public int Port { get; private set; } - - public QueryStringParameters Query { get; private set; } - - public Session Session { get; set; } - public HttpUser CurrentUser => Session.CurrentUser; - - public HeaderContainer RequestHeaders => requestHeaders; - - MemoryStream contentStream; - public MemoryStream ContentStream + public HttpRequest(HTTPServer httpServer, Request baseRequest) { - get + Server = httpServer; + BaseRequest = baseRequest; + + if (Enum.TryParse(BaseRequest.Method, out HttpMethod httpMethod)) + Method = httpMethod; + else + Method = HttpMethod.UNKOWN; + + Headers.TryGetValue("Host", out string host); + + if (Headers.TryGetValue("X-Forwarded-Host", out string forwardedHost)) + host = forwardedHost; + if (Headers.TryGetValue("X-Forwarded-For", out string forwardedFor)) + ClientAddress = IPAddress.Parse(forwardedFor.ReadToken(',')); + if (Headers.TryGetValue("X-Forwarded-Proto", out string forwardedProto)) + TLS = forwardedProto.Equals("https"); + + if (Headers.TryGetValue("Forwarded", out string forwarded)) { - if (contentStream == null) - ReadRequestBody(); - return contentStream; - } - } - public TextReader ContentReader - { - get - { - if (contentReader == null) - contentReader = new StreamReader(ContentStream); - return contentReader; - } - } - - int requestBodyLength; - byte[] requestBody; - StreamReader contentReader; - - Stream connectionStream; - UnbufferedStreamReader connectionReader; - - public Stream GetConnectionStream() => connectionStream; - - public HttpRequest(HTTPServer httpServer, Stream clientStream, Endpoint localEndpoint, Endpoint remoteEndpoint) - { - HTTPServer = httpServer; - connectionStream = clientStream; - connectionReader = new UnbufferedStreamReader(connectionStream); - - LocalEndpoint = localEndpoint; - RemoteEndpoint = remoteEndpoint; - - ReadRequestLine(); - - requestHeaders = HTTP.ReadHeader(connectionReader); - requestCookies = new Dictionary(); - requestParameters = new Dictionary(); - - Setup(); - - requestBodyLength = int.Parse(GetRequestHeader("content-length", "0")); - } - - void ReadRequestLine() - { - string requestLine = connectionReader.ReadLine(); - - if (requestLine == null) - throw new ConnectionClosedException("UnbufferedStreamReader.ReadLine() returned null"); - - string[] requestTokens = requestLine.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); - - if (requestTokens.Length != 3) - throw new BadRequestException(); - - HttpMethod = (HttpMethod)Enum.Parse(typeof(HttpMethod), requestTokens[0]); - RequestURL = requestTokens[1]; - Protocol = requestTokens[2]; - } - - public void ReadRequestBody() - { - requestBody = new byte[requestBodyLength]; - - if (requestBodyLength > 0) - { - int nRead = 0; - int length = requestBodyLength; - - while (length > 0) - { - int nr = connectionStream.Read(requestBody, nRead, length); - if (nr > 0) - { - nRead += nr; - length -= nr; - } - } + // ToDo: Implement parser } - contentStream = new MemoryStream(requestBody); - } - - public void FinishRequest() - { - if ((requestBodyLength > 0) && (requestBody == null)) + int colon = host.IndexOf(':'); + if (colon != -1) { - int nRead = 0; - int length = requestBodyLength; - byte[] discard = new byte[8192]; - - while (length > 0) - { - int nr = connectionStream.Read(discard,0,length > discard.Length ? discard.Length : length); - if (nr > 0) - { - nRead += nr; - length -= nr; - } - } + Host = host.Substring(0, colon).Trim(); + Port = int.Parse(host.Substring(colon + 1).Trim()); } + else + { + Host = host.Trim(); + } + + BaseUri = new UriBuilder(TLS ? "https:" : "http:", Host, Port).Uri; + RequestUri = new Uri(BaseUri, BaseRequest.RequestUri); + Query = new QueryStringParameters(RequestUri.Query); + + if (Headers.TryGetValue("Cookie", out string cookies)) + SetupCookies(cookies); } - public void MakeCurrent() => current.Value = this; - public static void ClearCurrent() => current.Value = null; - - private void Setup() + private void SetupCookies(string cookies) { - SetupResourceURI(); - SetupCookies(); - } - - /* - * SetupResourceURI() - * - * Setup the following fields: - * - * - Hostname - * - Port - * - BaseURI - * - URI - * - Query - * - */ - private void SetupResourceURI() - { - String host = GetRequestHeader("HOST"); - String[] hostTokens = host.Split(':'); - - Hostname = hostTokens[0]; - Port = (hostTokens.Length > 1) ? int.Parse(hostTokens[1]) : LocalEndpoint.Port; - BaseURI = new UriBuilder("http", Hostname, Port).Uri; - URI = new Uri(BaseURI, RequestURL); - Query = new QueryStringParameters(URI.Query); - } - - private void SetupCookies() - { - string cookies = GetRequestHeader("COOKIE"); foreach (String cookie in cookies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { string[] c = cookie.Split(new char[] { '=' }, 2); @@ -207,56 +95,47 @@ namespace ln.http } public override string ToString() - { + { //return string.Format("[HttpRequest: RemoteEndpoint={0}, Hostname={1} Port={2} URI={4}, Method={4}, RequestURL={5}, Protocol={6} Query={7}]", RemoteEndpoint, URI, Method, RequestURL, Protocol, Hostname, Port,Query); return base.ToString(); - } + } public String GetRequestHeader(String name) { return GetRequestHeader(name, ""); } + public String GetRequestHeader(String name, String def) - { - name = name.ToUpper(); - - if (requestHeaders.ContainsKey(name)) - return requestHeaders[name].Value; - - return def; - } - - public String[] RequestHeaderNames => requestHeaders.Keys.ToArray(); + { + if (Headers.TryGetValue(name, out string value)) + return value; + return def; + } public String[] CookieNames => requestCookies.Keys.ToArray(); - public bool ContainsCookie(String name) - { - return this.requestCookies.ContainsKey(name); - } - public String GetCookie(String name) - { - return requestCookies[name]; - } + public bool ContainsCookie(String name) => this.requestCookies.ContainsKey(name); + public String GetCookie(String name) => requestCookies[name]; + + public bool TryGetCookie(string cookieName, out string cookieValue) => + requestCookies.TryGetValue(cookieName, out cookieValue); public bool ContainsParameter(string parameterName) => requestParameters.ContainsKey(parameterName); public String GetParameter(String parameterName) => GetParameter(parameterName, null); - public String GetParameter(String parameterName,String defaultValue) + + public String GetParameter(String parameterName, String defaultValue) { if (!requestParameters.TryGetValue(parameterName, out string value)) value = defaultValue; return value; } - public void SetParameter(String parameterName,String parameterValue) => requestParameters[parameterName] = parameterValue; + + public void SetParameter(String parameterName, String parameterValue) => + requestParameters[parameterName] = parameterValue; + public IEnumerable ParameterNames => requestParameters.Keys; - - public string self() - { - return BaseURI.ToString(); - } - - public HttpResponse Redirect(string location, params object[] p) => Redirect(303, location, p); + public HttpResponse Redirect(int status, string location, params object[] p) { location = string.Format(location, p); @@ -268,11 +147,19 @@ namespace ln.http } - public void Dispose() + public HttpResponse Redirect(HttpStatusCode statusCode, string location, params object[] p) { - contentReader?.Dispose(); - ContentStream?.Dispose(); + if (p?.Length > 0) + location = string.Format(location, p); + + HttpResponse response = new HttpResponse(statusCode); + response.SetHeader("Location", location); + return response; } + public void Dispose() + { + ContentStream?.Dispose(); + } } -} +} \ No newline at end of file diff --git a/ln.http/HttpResponse.cs b/ln.http/HttpResponse.cs index 1ca2995..e03c563 100644 --- a/ln.http/HttpResponse.cs +++ b/ln.http/HttpResponse.cs @@ -7,8 +7,6 @@ namespace ln.http { public class HttpResponse { - //public HttpRequest HttpRequest { get; } - public Stream ContentStream { get; private set; } public TextWriter ContentWriter { get; private set; } public bool HasCustomContentStream { get; private set; } @@ -16,7 +14,6 @@ namespace ln.http Dictionary> headers = new Dictionary>(); List cookies = new List(); - public HttpResponse() : this(HttpStatusCode.OK) { } @@ -132,6 +129,9 @@ namespace ln.http public static HttpResponse Accepted() => new HttpResponse(HttpStatusCode.Accepted); public static HttpResponse NoContent() => new HttpResponse(HttpStatusCode.NoContent); + public static HttpResponse MultiStatus() => + new HttpResponse(HttpStatusCode.MultiStatus).Header("content-type", "application/xml"); + public static HttpResponse MovedPermanently() => new HttpResponse(HttpStatusCode.MovedPermanently); public static HttpResponse TemporaryRedirect() => new HttpResponse(HttpStatusCode.TemporaryRedirect); public static HttpResponse PermanentRedirect() => new HttpResponse(HttpStatusCode.PermanentRedirect); @@ -142,6 +142,8 @@ namespace ln.http public static HttpResponse Forbidden() => new HttpResponse(HttpStatusCode.Forbidden); public static HttpResponse MethodNotAllowed() => new HttpResponse(HttpStatusCode.MethodNotAllowed); public static HttpResponse RequestTimeout() => new HttpResponse(HttpStatusCode.RequestTimeout); + public static HttpResponse Conflict() => new HttpResponse(HttpStatusCode.Conflict); + public static HttpResponse UnsupportedMediaType() => new HttpResponse(HttpStatusCode.UnsupportedMediaType); public static HttpResponse ImATeapot() => new HttpResponse(HttpStatusCode.ImATeapot); public static HttpResponse UpgradeRequired() => new HttpResponse(HttpStatusCode.UpgradeRequired); @@ -169,19 +171,12 @@ namespace ln.http return this; } - - - - - public virtual void SendResponse(Stream stream, HttpRequest httpRequest) + public virtual void WriteTo(Stream stream) { - httpRequest.FinishRequest(); SetHeader("Content-Length", ContentStream.Length.ToString()); - StreamWriter streamWriter = new StreamWriter(stream); - streamWriter.NewLine = "\r\n"; - - streamWriter.WriteLine("{0} {1} {2}", httpRequest.Protocol, (int)HttpStatusCode, HttpStatusCode.ToString()); + StreamWriter streamWriter = new StreamWriter(stream) {NewLine = "\r\n"}; + streamWriter.WriteLine("{0} {1} {2}", "HTTP/1.1", (int)HttpStatusCode, HttpStatusCode.ToString()); foreach (String headerName in GetHeaderNames()) { streamWriter.WriteLine("{0}: {1}", headerName, GetHeader(headerName)); @@ -202,9 +197,5 @@ namespace ln.http stream.Flush(); } - - - - } } diff --git a/ln.http/HttpRouter.cs b/ln.http/HttpRouter.cs deleted file mode 100644 index b58fc57..0000000 --- a/ln.http/HttpRouter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using ln.logging; -using ln.http.router; -namespace ln.http -{ - //public abstract class HttpRouter : IHttpRouter - //{ - // public HttpRouter() - // { - // } - - // public abstract IHTTPResource FindResource(HttpRequest httpRequest); - - // public virtual HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest) - // { - // try - // { - // IHTTPResource resource = FindResource(httpRequest); - // return resource.GetResponse(httpRequest); - // } catch (Exception e) - // { - // Logging.Log(e); - // if (httpRequest != null) - // { - // HttpResponse httpResponse = new HttpResponse(httpRequest); - // httpResponse.StatusCode = 500; - // httpResponse.ContentWriter.WriteLine("500 Internal Server Error"); - - // return httpResponse; - // } - // return null; - // } - // } - - //} -} diff --git a/ln.http/HttpUser.cs b/ln.http/HttpUser.cs deleted file mode 100644 index 79cef7c..0000000 --- a/ln.http/HttpUser.cs +++ /dev/null @@ -1,30 +0,0 @@ -// /** -// * File: HttpUser.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; - -namespace ln.http -{ - public class HttpUser - { - public String AuthenticationName { get; private set; } - public virtual String DisplayName { get; private set; } - - public long AccessRightsMask { get; private set; } - - public HttpUser() - { - AuthenticationName = ""; - DisplayName = "Anonymous"; - AccessRightsMask = 0; - } - - - } -} diff --git a/ln.http/IHTTPResource.cs b/ln.http/IHTTPResource.cs deleted file mode 100644 index b48c503..0000000 --- a/ln.http/IHTTPResource.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; -namespace ln.http -{ - public interface IHTTPResource - { - HttpResponse GetResponse(HttpRequest httpRequest); - } -} diff --git a/ln.http/client/HttpClientRequest.cs b/ln.http/client/HttpClientRequest.cs index 3e272f3..71903ed 100644 --- a/ln.http/client/HttpClientRequest.cs +++ b/ln.http/client/HttpClientRequest.cs @@ -3,6 +3,8 @@ using ln.type; using System.IO; using System.Net.Sockets; using System.Net.Security; +using ln.protocols.helper; + namespace ln.http.client { public class HttpClientRequest @@ -19,7 +21,7 @@ namespace ln.http.client } } - public HttpHeaders Headers { get; } = new HttpHeaders(); + public HeaderContainer Headers { get; } = new HeaderContainer(); public String Method { get; set; } URI uri; diff --git a/ln.http/connections/Connection.cs b/ln.http/connections/Connection.cs index 05e17fe..51395f1 100644 --- a/ln.http/connections/Connection.cs +++ b/ln.http/connections/Connection.cs @@ -10,9 +10,11 @@ using System; using ln.type; using System.IO; +using System.Text; using ln.logging; using ln.http.listener; using ln.http.exceptions; +using ln.protocols.helper; namespace ln.http.connections { @@ -34,7 +36,9 @@ namespace ln.http.connections { try { - return new HttpRequest(httpServer, GetStream(), Listener.LocalEndpoint, new Endpoint(RemoteHost, RemotePort)); + if (HttpLikeProtocolReader.ReadRequest(GetStream(), Encoding.UTF8, out Request request)) + return new HttpRequest(httpServer, request); + return null; } catch (IOException) { return null; diff --git a/ln.http/connections/HttpsConnection.cs b/ln.http/connections/HttpsConnection.cs index 3c7c894..aaa581a 100644 --- a/ln.http/connections/HttpsConnection.cs +++ b/ln.http/connections/HttpsConnection.cs @@ -9,7 +9,6 @@ // **/ using System; using System.IO; -using System.Security.AccessControl; using ln.type; using System.Net.Security; using ln.http.listener; @@ -29,6 +28,7 @@ namespace ln.http.connections { Connection = connection; sslStream = new SslStream(connection.GetStream(),false, null, localCertificateSelectionCallback); + sslStream.AuthenticateAsServer(new System.Security.Cryptography.X509Certificates.X509Certificate()); } public override HttpRequest ReadRequest(HTTPServer server) diff --git a/ln.http/exceptions/HttpException.cs b/ln.http/exceptions/HttpException.cs index b57d44c..83df3a2 100644 --- a/ln.http/exceptions/HttpException.cs +++ b/ln.http/exceptions/HttpException.cs @@ -6,6 +6,8 @@ namespace ln.http.exceptions { public int StatusCode { get; } = 500; + public virtual HttpResponse HttpResponse { get; protected set; } + public HttpException(String message) : base(message) { diff --git a/ln.http/listener/HttpListener.cs b/ln.http/listener/HttpListener.cs index 7147e7d..21dc57b 100644 --- a/ln.http/listener/HttpListener.cs +++ b/ln.http/listener/HttpListener.cs @@ -25,6 +25,8 @@ namespace ln.http.listener { } + public override Endpoint LocalEndpoint => new Endpoint(tcpListener.LocalEndpoint); + public override Connection Accept() => new HttpConnection(this,tcpListener.AcceptTcpClient()); public override bool IsOpen => (tcpListener != null); diff --git a/ln.http/listener/Listener.cs b/ln.http/listener/Listener.cs index 7960226..71c8218 100644 --- a/ln.http/listener/Listener.cs +++ b/ln.http/listener/Listener.cs @@ -17,7 +17,7 @@ namespace ln.http.listener public IPv6 Listen { get; } public int Port { get; } - public Endpoint LocalEndpoint => new Endpoint(Listen, Port); + public virtual Endpoint LocalEndpoint => new Endpoint(Listen, Port); public abstract bool IsOpen { get; } diff --git a/ln.http/ln.http.csproj b/ln.http/ln.http.csproj index 07ef25e..3f832fc 100644 --- a/ln.http/ln.http.csproj +++ b/ln.http/ln.http.csproj @@ -1,22 +1,27 @@  - netcoreapp3.1 + net5.0 true - 0.4.2 + 0.4.3-ci Harald Wolff-Thobaben l--n.de (c) 2020 Harald Wolff-Thobaben http server + 9 - + + + + + diff --git a/ln.http/message/Header.cs b/ln.http/message/Header.cs deleted file mode 100644 index cf7a026..0000000 --- a/ln.http/message/Header.cs +++ /dev/null @@ -1,159 +0,0 @@ -// /** -// * File: Header.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Linq; -using System.Net.Sockets; -namespace ln.http.message -{ - public class Header - { - public string Name { get; } - - string rawvalue; - public string RawValue { - get => rawvalue; - set => SetValue(value); - } - - string comments; - public string Comments => comments; - - string value; - public string Value - { - get => value; - set => SetValue(value); - } - - Dictionary parameters; - - public Header(string headerLine) - { - int colon = headerLine.IndexOf(':'); - if (colon == -1) - throw new FormatException("expected to find :"); - - Name = headerLine.Substring(0, colon).ToUpper(); - SetValue(headerLine.Substring(colon + 1)); - } - public Header(string name, string value) - { - Name = name.ToUpper(); - SetValue(value); - } - - public void SetValue(string newValue) - { - rawvalue = newValue; - value = ParseValue(new StringReader(newValue.Trim()),out comments); - - // at least MIME Content-* header follow the parameter syntax... - if (Name.StartsWith("CONTENT-", StringComparison.InvariantCulture)) - { - ParseParameters(); - } - } - - public bool ContainsParameter(string parameterName) => parameters.ContainsKey(parameterName.ToUpper()); - public string GetParameter(string parameterName) => parameters[parameterName.ToUpper()]; - public string GetParameter(string parameterName,string defaultValue) => parameters[parameterName.ToUpper()]; - - string ParseComment(TextReader reader) - { - StringBuilder commentBuilder = new StringBuilder(); - ParseComment(reader, commentBuilder); - return commentBuilder.ToString(); - } - void ParseComment(TextReader reader,StringBuilder commentBuilder) - { - int ch; - while (((ch = reader.Read()) != -1) && (ch != ')')) - commentBuilder.Append((char)ch); - } - public virtual string ParseValue(TextReader reader,out string parsedComments) - { - StringBuilder stringBuilder = new StringBuilder(); - StringBuilder commentBuilder = new StringBuilder(); - - int ch; - while (((ch = reader.Read())!=-1)) - { - if (ch == '(') - { - commentBuilder.Append(ParseComment(reader)); - } else - { - stringBuilder.Append((char)ch); - } - } - parsedComments = commentBuilder.ToString().Trim(); - return stringBuilder.ToString().Trim(); - } - - public void ParseParameters() - { - if (parameters != null) - return; - - parameters = new Dictionary(); - - int semicolon = value.IndexOf(';'); - if (semicolon > 0) - { - TokenReader tokenReader = new TokenReader(new StringReader(value.Substring(semicolon))); - while (tokenReader.Peek() != -1) - { - if (tokenReader.Read() != ';') - throw new FormatException(); - - string pName = tokenReader.ReadToken().ToUpper(); - if (tokenReader.Read() != '=') - throw new FormatException("expected ="); - - string pValue = (tokenReader.Peek() == '"') ? tokenReader.ReadQuotedString() : tokenReader.ReadToken(); - parameters.Add(pName, pValue); - } - - value = value.Substring(0, semicolon).Trim(); - } - } - - //void parseValue(string v) - //{ - // rawValue = v; - // TokenReader tokenReader = new TokenReader(parseComments(new StringReader(v))); - // StringBuilder stringBuilder = new StringBuilder(); - - // int ch; - // while (((ch = tokenReader.Read()) != -1) && (ch != ';')) - // stringBuilder.Append((char)ch); - - // Value = stringBuilder.ToString(); - - // while (tokenReader.Peek() != -1) - // { - // string pName = tokenReader.ReadToken(); - // if (tokenReader.Read() != '=') - // throw new FormatException("expected ="); - - // string pValue = (tokenReader.Peek() == '"') ? tokenReader.ReadQuotedString() : tokenReader.ReadToken(); - // parameters.Add(pName, pValue); - // } - - - //} - - public override int GetHashCode() => Name.GetHashCode(); - public override bool Equals(object obj) => (obj is Header you) && Name.Equals(you.Name); - } -} diff --git a/ln.http/message/HeaderContainer.cs b/ln.http/message/HeaderContainer.cs deleted file mode 100644 index b4d0638..0000000 --- a/ln.http/message/HeaderContainer.cs +++ /dev/null @@ -1,76 +0,0 @@ -// /** -// * File: HeaderContainer.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using ln.http.io; -namespace ln.http.message -{ - public class HeaderContainer - { - Dictionary headers = new Dictionary(); - - public HeaderContainer() - { - } - public HeaderContainer(Stream stream):this(new UnbufferedStreamReader(stream)) - { - } - public HeaderContainer(TextReader reader) - { - List headerLines = new List(); - string currentline = reader.ReadLine(); - while (!currentline.Equals(string.Empty)) - { - if (char.IsWhiteSpace(currentline[0])) - { - headerLines[headerLines.Count - 1] = headerLines[headerLines.Count - 1] + currentline; - } - else - { - headerLines.Add(currentline); - } - currentline = reader.ReadLine(); - } - - foreach (string headerLine in headerLines) - { - Header header = new Header(headerLine); - headers.Add(header.Name, header); - } - } - - public Header this[string name] - { - get => headers[name.ToUpper()]; - } - - public void Add(Header header)=> headers.Add(header.Name, header); - - public bool ContainsKey(string name) => headers.ContainsKey(name.ToUpper()); - public bool Contains(string name) => headers.ContainsKey(name.ToUpper()); - public string Get(string name) => this[name].Value; - public void Set(string name,string value) - { - name = name.ToUpper(); - if (!headers.TryGetValue(name,out Header header)) - { - header = new Header(name); - headers.Add(name, header); - } - header.Value = value; - } - public void Remove(string name) => headers.Remove(name.ToUpper()); - - public IEnumerable Keys => headers.Keys; - - } -} diff --git a/ln.http/message/Message.cs b/ln.http/message/Message.cs deleted file mode 100644 index f34bc3a..0000000 --- a/ln.http/message/Message.cs +++ /dev/null @@ -1,153 +0,0 @@ -// /** -// * File: Message.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Globalization; -using ln.http.io; -using ln.type; -using ln.http.message.parser; -namespace ln.http.message -{ - public class Message - { - public HeaderContainer Headers { get; private set; } - - byte[] bodyData; - int bodyOffset; - int bodyLength; - - List parts; - - bool isMultipart; - public bool IsMultipart => isMultipart; - - public Message() - { - Setup(new HeaderContainer(), new byte[0], 0, 0); - } - - public Message(HeaderContainer headers, byte[] body) - : this(headers, body, 0, body.Length) { } - - public Message(HeaderContainer headers, byte[] body, int offset, int length) - { - Setup(headers, body, offset, length); - } - - public Message(byte[] body, int offset, int length) - { - MemoryStream memoryStream = new MemoryStream(body, offset, length); - HeaderContainer headers = MIME.ReadHeader(new UnbufferedStreamReader(memoryStream)); - - if (memoryStream.Position >= length) - throw new FormatException("MIME header section too long"); - - Setup(headers, body, offset + (int)memoryStream.Position, length - (int)memoryStream.Position); - } - - public Message(Stream stream) - { - HeaderContainer headers = MIME.ReadHeader(new UnbufferedStreamReader(stream)); - - byte[] data = stream.ReadToEnd(); - - Setup(headers, data, 0, data.Length); - } - - private void Setup(HeaderContainer headers, byte[] body, int offset, int length) - { - Headers = headers; - - bodyData = body; - bodyOffset = offset; - bodyLength = length; - - string ct = Headers["Content-Type"].Value; - isMultipart = ct.StartsWith("multipart/", StringComparison.InvariantCulture) || ct.StartsWith("message/", StringComparison.InvariantCulture); - } - - public void ReadParts() - { - parts = new List(); - - if (isMultipart) - { - string boundary = Headers["Content-Type"].GetParameter("boundary"); - string delimiter = "--" + boundary; - int[] indeces = FindIndeces(bodyData, bodyOffset, bodyLength, Encoding.ASCII.GetBytes(delimiter)); - - for (int n = 1; n < indeces.Length; n++) - { - Message part = new Message(bodyData, indeces[n - 1], indeces[n] - indeces[n - 1]); - parts.Add(part); - } - - } - } - - int[] FindIndeces(byte[] data,int offset,int length,byte[] pattern) - { - List offsets = new List(); - List validated = new List(); - - for (int n = offset; n < (length - pattern.Length); n++) - { - int p = 0; - while ((p < pattern.Length) && (data[n + p] == pattern[p])) - p++; - - if (p == pattern.Length) - { - if ((n == offset) || ((n >= (offset + 2)) && (data[offset + n - 2] == '\r') && (data[offset + n - 1] == '\n'))) - { - n += pattern.Length; - - while ((n < (offset + length)) && (data[n - 2] != '\r') && (data[n - 1] != '\n')) - n++; - - validated.Add(n); - - - if (((offset + length) > (n + 1)) && (data[n] == '-') && (data[n + 1] == '-')) - break; - } - } - } - - return validated.ToArray(); - } - - - public Stream OpenBodyStream() => new MemoryStream(bodyData, bodyOffset, bodyLength); - - public IEnumerable Parts - { - get - { - if (parts == null) - ReadParts(); - return parts; - } - } - - public bool HasHeader(string name) => Headers.Contains(name); - public Header GetHeader(string name) => Headers[name]; - public void SetHeader(string name, string value) => Headers.Set(name, value); - public void RemoveHeader(String name) => Headers.Remove(name); - - public override string ToString() - { - return base.ToString(); - } - - } -} diff --git a/ln.http/message/MimeTypeMap.cs b/ln.http/message/MimeTypeMap.cs deleted file mode 100644 index 47766a4..0000000 --- a/ln.http/message/MimeTypeMap.cs +++ /dev/null @@ -1,767 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace ln.http.message -{ - public static class MimeTypeMap - { - private static readonly Lazy> _mappings = new Lazy>(BuildMappings); - - private static IDictionary BuildMappings() - { - var mappings = new Dictionary(StringComparer.OrdinalIgnoreCase) { - - #region Big freaking list of mime types - - // maps both ways, - // extension -> mime type - // and - // mime type -> extension - // - // any mime types on left side not pre-loaded on right side, are added automatically - // some mime types can map to multiple extensions, so to get a deterministic mapping, - // add those to the dictionary specifcially - // - // combination of values from Windows 7 Registry and - // from C:\Windows\System32\inetsrv\config\applicationHost.config - // some added, including .7z and .dat - // - // Some added based on http://www.iana.org/assignments/media-types/media-types.xhtml - // which lists mime types, but not extensions - // - {".323", "text/h323"}, - {".3g2", "video/3gpp2"}, - {".3gp", "video/3gpp"}, - {".3gp2", "video/3gpp2"}, - {".3gpp", "video/3gpp"}, - {".7z", "application/x-7z-compressed"}, - {".aa", "audio/audible"}, - {".AAC", "audio/aac"}, - {".aaf", "application/octet-stream"}, - {".aax", "audio/vnd.audible.aax"}, - {".ac3", "audio/ac3"}, - {".aca", "application/octet-stream"}, - {".accda", "application/msaccess.addin"}, - {".accdb", "application/msaccess"}, - {".accdc", "application/msaccess.cab"}, - {".accde", "application/msaccess"}, - {".accdr", "application/msaccess.runtime"}, - {".accdt", "application/msaccess"}, - {".accdw", "application/msaccess.webapplication"}, - {".accft", "application/msaccess.ftemplate"}, - {".acx", "application/internet-property-stream"}, - {".AddIn", "text/xml"}, - {".ade", "application/msaccess"}, - {".adobebridge", "application/x-bridge-url"}, - {".adp", "application/msaccess"}, - {".ADT", "audio/vnd.dlna.adts"}, - {".ADTS", "audio/aac"}, - {".afm", "application/octet-stream"}, - {".ai", "application/postscript"}, - {".aif", "audio/aiff"}, - {".aifc", "audio/aiff"}, - {".aiff", "audio/aiff"}, - {".air", "application/vnd.adobe.air-application-installer-package+zip"}, - {".amc", "application/mpeg"}, - {".anx", "application/annodex"}, - {".apk", "application/vnd.android.package-archive" }, - {".application", "application/x-ms-application"}, - {".art", "image/x-jg"}, - {".asa", "application/xml"}, - {".asax", "application/xml"}, - {".ascx", "application/xml"}, - {".asd", "application/octet-stream"}, - {".asf", "video/x-ms-asf"}, - {".ashx", "application/xml"}, - {".asi", "application/octet-stream"}, - {".asm", "text/plain"}, - {".asmx", "application/xml"}, - {".aspx", "application/xml"}, - {".asr", "video/x-ms-asf"}, - {".asx", "video/x-ms-asf"}, - {".atom", "application/atom+xml"}, - {".au", "audio/basic"}, - {".avi", "video/x-msvideo"}, - {".axa", "audio/annodex"}, - {".axs", "application/olescript"}, - {".axv", "video/annodex"}, - {".bas", "text/plain"}, - {".bcpio", "application/x-bcpio"}, - {".bin", "application/octet-stream"}, - {".bmp", "image/bmp"}, - {".c", "text/plain"}, - {".cab", "application/octet-stream"}, - {".caf", "audio/x-caf"}, - {".calx", "application/vnd.ms-office.calx"}, - {".cat", "application/vnd.ms-pki.seccat"}, - {".cc", "text/plain"}, - {".cd", "text/plain"}, - {".cdda", "audio/aiff"}, - {".cdf", "application/x-cdf"}, - {".cer", "application/x-x509-ca-cert"}, - {".cfg", "text/plain"}, - {".chm", "application/octet-stream"}, - {".class", "application/x-java-applet"}, - {".clp", "application/x-msclip"}, - {".cmd", "text/plain"}, - {".cmx", "image/x-cmx"}, - {".cnf", "text/plain"}, - {".cod", "image/cis-cod"}, - {".config", "application/xml"}, - {".contact", "text/x-ms-contact"}, - {".coverage", "application/xml"}, - {".cpio", "application/x-cpio"}, - {".cpp", "text/plain"}, - {".crd", "application/x-mscardfile"}, - {".crl", "application/pkix-crl"}, - {".crt", "application/x-x509-ca-cert"}, - {".cs", "text/plain"}, - {".csdproj", "text/plain"}, - {".csh", "application/x-csh"}, - {".csproj", "text/plain"}, - {".css", "text/css"}, - {".csv", "text/csv"}, - {".cur", "application/octet-stream"}, - {".cxx", "text/plain"}, - {".dat", "application/octet-stream"}, - {".datasource", "application/xml"}, - {".dbproj", "text/plain"}, - {".dcr", "application/x-director"}, - {".def", "text/plain"}, - {".deploy", "application/octet-stream"}, - {".der", "application/x-x509-ca-cert"}, - {".dgml", "application/xml"}, - {".dib", "image/bmp"}, - {".dif", "video/x-dv"}, - {".dir", "application/x-director"}, - {".disco", "text/xml"}, - {".divx", "video/divx"}, - {".dll", "application/x-msdownload"}, - {".dll.config", "text/xml"}, - {".dlm", "text/dlm"}, - {".doc", "application/msword"}, - {".docm", "application/vnd.ms-word.document.macroEnabled.12"}, - {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, - {".dot", "application/msword"}, - {".dotm", "application/vnd.ms-word.template.macroEnabled.12"}, - {".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"}, - {".dsp", "application/octet-stream"}, - {".dsw", "text/plain"}, - {".dtd", "text/xml"}, - {".dtsConfig", "text/xml"}, - {".dv", "video/x-dv"}, - {".dvi", "application/x-dvi"}, - {".dwf", "drawing/x-dwf"}, - {".dwg", "application/acad"}, - {".dwp", "application/octet-stream"}, - {".dxf", "application/x-dxf" }, - {".dxr", "application/x-director"}, - {".eml", "message/rfc822"}, - {".emz", "application/octet-stream"}, - {".eot", "application/vnd.ms-fontobject"}, - {".eps", "application/postscript"}, - {".es", "application/ecmascript"}, - {".etl", "application/etl"}, - {".etx", "text/x-setext"}, - {".evy", "application/envoy"}, - {".exe", "application/vnd.microsoft.portable-executable"}, - {".exe.config", "text/xml"}, - {".f4v", "video/mp4"}, - {".fdf", "application/vnd.fdf"}, - {".fif", "application/fractals"}, - {".filters", "application/xml"}, - {".fla", "application/octet-stream"}, - {".flac", "audio/flac"}, - {".flr", "x-world/x-vrml"}, - {".flv", "video/x-flv"}, - {".fsscript", "application/fsharp-script"}, - {".fsx", "application/fsharp-script"}, - {".generictest", "application/xml"}, - {".gif", "image/gif"}, - {".gpx", "application/gpx+xml"}, - {".group", "text/x-ms-group"}, - {".gsm", "audio/x-gsm"}, - {".gtar", "application/x-gtar"}, - {".gz", "application/x-gzip"}, - {".h", "text/plain"}, - {".hdf", "application/x-hdf"}, - {".hdml", "text/x-hdml"}, - {".hhc", "application/x-oleobject"}, - {".hhk", "application/octet-stream"}, - {".hhp", "application/octet-stream"}, - {".hlp", "application/winhlp"}, - {".hpp", "text/plain"}, - {".hqx", "application/mac-binhex40"}, - {".hta", "application/hta"}, - {".htc", "text/x-component"}, - {".htm", "text/html"}, - {".html", "text/html"}, - {".htt", "text/webviewhtml"}, - {".hxa", "application/xml"}, - {".hxc", "application/xml"}, - {".hxd", "application/octet-stream"}, - {".hxe", "application/xml"}, - {".hxf", "application/xml"}, - {".hxh", "application/octet-stream"}, - {".hxi", "application/octet-stream"}, - {".hxk", "application/xml"}, - {".hxq", "application/octet-stream"}, - {".hxr", "application/octet-stream"}, - {".hxs", "application/octet-stream"}, - {".hxt", "text/html"}, - {".hxv", "application/xml"}, - {".hxw", "application/octet-stream"}, - {".hxx", "text/plain"}, - {".i", "text/plain"}, - {".ico", "image/x-icon"}, - {".ics", "application/octet-stream"}, - {".idl", "text/plain"}, - {".ief", "image/ief"}, - {".iii", "application/x-iphone"}, - {".inc", "text/plain"}, - {".inf", "application/octet-stream"}, - {".ini", "text/plain"}, - {".inl", "text/plain"}, - {".ins", "application/x-internet-signup"}, - {".ipa", "application/x-itunes-ipa"}, - {".ipg", "application/x-itunes-ipg"}, - {".ipproj", "text/plain"}, - {".ipsw", "application/x-itunes-ipsw"}, - {".iqy", "text/x-ms-iqy"}, - {".isp", "application/x-internet-signup"}, - {".isma", "application/octet-stream"}, - {".ismv", "application/octet-stream"}, - {".ite", "application/x-itunes-ite"}, - {".itlp", "application/x-itunes-itlp"}, - {".itms", "application/x-itunes-itms"}, - {".itpc", "application/x-itunes-itpc"}, - {".IVF", "video/x-ivf"}, - {".jar", "application/java-archive"}, - {".java", "application/octet-stream"}, - {".jck", "application/liquidmotion"}, - {".jcz", "application/liquidmotion"}, - {".jfif", "image/pjpeg"}, - {".jnlp", "application/x-java-jnlp-file"}, - {".jpb", "application/octet-stream"}, - {".jpe", "image/jpeg"}, - {".jpeg", "image/jpeg"}, - {".jpg", "image/jpeg"}, - {".js", "application/javascript"}, - {".json", "application/json"}, - {".jsx", "text/jscript"}, - {".jsxbin", "text/plain"}, - {".latex", "application/x-latex"}, - {".library-ms", "application/windows-library+xml"}, - {".lit", "application/x-ms-reader"}, - {".loadtest", "application/xml"}, - {".lpk", "application/octet-stream"}, - {".lsf", "video/x-la-asf"}, - {".lst", "text/plain"}, - {".lsx", "video/x-la-asf"}, - {".lzh", "application/octet-stream"}, - {".m13", "application/x-msmediaview"}, - {".m14", "application/x-msmediaview"}, - {".m1v", "video/mpeg"}, - {".m2t", "video/vnd.dlna.mpeg-tts"}, - {".m2ts", "video/vnd.dlna.mpeg-tts"}, - {".m2v", "video/mpeg"}, - {".m3u", "audio/x-mpegurl"}, - {".m3u8", "audio/x-mpegurl"}, - {".m4a", "audio/m4a"}, - {".m4b", "audio/m4b"}, - {".m4p", "audio/m4p"}, - {".m4r", "audio/x-m4r"}, - {".m4v", "video/x-m4v"}, - {".mac", "image/x-macpaint"}, - {".mak", "text/plain"}, - {".man", "application/x-troff-man"}, - {".manifest", "application/x-ms-manifest"}, - {".map", "text/plain"}, - {".master", "application/xml"}, - {".mbox", "application/mbox"}, - {".mda", "application/msaccess"}, - {".mdb", "application/x-msaccess"}, - {".mde", "application/msaccess"}, - {".mdp", "application/octet-stream"}, - {".me", "application/x-troff-me"}, - {".mfp", "application/x-shockwave-flash"}, - {".mht", "message/rfc822"}, - {".mhtml", "message/rfc822"}, - {".mid", "audio/mid"}, - {".midi", "audio/mid"}, - {".mix", "application/octet-stream"}, - {".mk", "text/plain"}, - {".mk3d", "video/x-matroska-3d"}, - {".mka", "audio/x-matroska"}, - {".mkv", "video/x-matroska"}, - {".mmf", "application/x-smaf"}, - {".mno", "text/xml"}, - {".mny", "application/x-msmoney"}, - {".mod", "video/mpeg"}, - {".mov", "video/quicktime"}, - {".movie", "video/x-sgi-movie"}, - {".mp2", "video/mpeg"}, - {".mp2v", "video/mpeg"}, - {".mp3", "audio/mpeg"}, - {".mp4", "video/mp4"}, - {".mp4v", "video/mp4"}, - {".mpa", "video/mpeg"}, - {".mpe", "video/mpeg"}, - {".mpeg", "video/mpeg"}, - {".mpf", "application/vnd.ms-mediapackage"}, - {".mpg", "video/mpeg"}, - {".mpp", "application/vnd.ms-project"}, - {".mpv2", "video/mpeg"}, - {".mqv", "video/quicktime"}, - {".ms", "application/x-troff-ms"}, - {".msg", "application/vnd.ms-outlook"}, - {".msi", "application/octet-stream"}, - {".mso", "application/octet-stream"}, - {".mts", "video/vnd.dlna.mpeg-tts"}, - {".mtx", "application/xml"}, - {".mvb", "application/x-msmediaview"}, - {".mvc", "application/x-miva-compiled"}, - {".mxf", "application/mxf"}, - {".mxp", "application/x-mmxp"}, - {".nc", "application/x-netcdf"}, - {".nsc", "video/x-ms-asf"}, - {".nws", "message/rfc822"}, - {".ocx", "application/octet-stream"}, - {".oda", "application/oda"}, - {".odb", "application/vnd.oasis.opendocument.database"}, - {".odc", "application/vnd.oasis.opendocument.chart"}, - {".odf", "application/vnd.oasis.opendocument.formula"}, - {".odg", "application/vnd.oasis.opendocument.graphics"}, - {".odh", "text/plain"}, - {".odi", "application/vnd.oasis.opendocument.image"}, - {".odl", "text/plain"}, - {".odm", "application/vnd.oasis.opendocument.text-master"}, - {".odp", "application/vnd.oasis.opendocument.presentation"}, - {".ods", "application/vnd.oasis.opendocument.spreadsheet"}, - {".odt", "application/vnd.oasis.opendocument.text"}, - {".oga", "audio/ogg"}, - {".ogg", "audio/ogg"}, - {".ogv", "video/ogg"}, - {".ogx", "application/ogg"}, - {".one", "application/onenote"}, - {".onea", "application/onenote"}, - {".onepkg", "application/onenote"}, - {".onetmp", "application/onenote"}, - {".onetoc", "application/onenote"}, - {".onetoc2", "application/onenote"}, - {".opus", "audio/ogg"}, - {".orderedtest", "application/xml"}, - {".osdx", "application/opensearchdescription+xml"}, - {".otf", "application/font-sfnt"}, - {".otg", "application/vnd.oasis.opendocument.graphics-template"}, - {".oth", "application/vnd.oasis.opendocument.text-web"}, - {".otp", "application/vnd.oasis.opendocument.presentation-template"}, - {".ots", "application/vnd.oasis.opendocument.spreadsheet-template"}, - {".ott", "application/vnd.oasis.opendocument.text-template"}, - {".oxt", "application/vnd.openofficeorg.extension"}, - {".p10", "application/pkcs10"}, - {".p12", "application/x-pkcs12"}, - {".p7b", "application/x-pkcs7-certificates"}, - {".p7c", "application/pkcs7-mime"}, - {".p7m", "application/pkcs7-mime"}, - {".p7r", "application/x-pkcs7-certreqresp"}, - {".p7s", "application/pkcs7-signature"}, - {".pbm", "image/x-portable-bitmap"}, - {".pcast", "application/x-podcast"}, - {".pct", "image/pict"}, - {".pcx", "application/octet-stream"}, - {".pcz", "application/octet-stream"}, - {".pdf", "application/pdf"}, - {".pfb", "application/octet-stream"}, - {".pfm", "application/octet-stream"}, - {".pfx", "application/x-pkcs12"}, - {".pgm", "image/x-portable-graymap"}, - {".pic", "image/pict"}, - {".pict", "image/pict"}, - {".pkgdef", "text/plain"}, - {".pkgundef", "text/plain"}, - {".pko", "application/vnd.ms-pki.pko"}, - {".pls", "audio/scpls"}, - {".pma", "application/x-perfmon"}, - {".pmc", "application/x-perfmon"}, - {".pml", "application/x-perfmon"}, - {".pmr", "application/x-perfmon"}, - {".pmw", "application/x-perfmon"}, - {".png", "image/png"}, - {".pnm", "image/x-portable-anymap"}, - {".pnt", "image/x-macpaint"}, - {".pntg", "image/x-macpaint"}, - {".pnz", "image/png"}, - {".pot", "application/vnd.ms-powerpoint"}, - {".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"}, - {".potx", "application/vnd.openxmlformats-officedocument.presentationml.template"}, - {".ppa", "application/vnd.ms-powerpoint"}, - {".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"}, - {".ppm", "image/x-portable-pixmap"}, - {".pps", "application/vnd.ms-powerpoint"}, - {".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"}, - {".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"}, - {".ppt", "application/vnd.ms-powerpoint"}, - {".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"}, - {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, - {".prf", "application/pics-rules"}, - {".prm", "application/octet-stream"}, - {".prx", "application/octet-stream"}, - {".ps", "application/postscript"}, - {".psc1", "application/PowerShell"}, - {".psd", "application/octet-stream"}, - {".psess", "application/xml"}, - {".psm", "application/octet-stream"}, - {".psp", "application/octet-stream"}, - {".pst", "application/vnd.ms-outlook"}, - {".pub", "application/x-mspublisher"}, - {".pwz", "application/vnd.ms-powerpoint"}, - {".qht", "text/x-html-insertion"}, - {".qhtm", "text/x-html-insertion"}, - {".qt", "video/quicktime"}, - {".qti", "image/x-quicktime"}, - {".qtif", "image/x-quicktime"}, - {".qtl", "application/x-quicktimeplayer"}, - {".qxd", "application/octet-stream"}, - {".ra", "audio/x-pn-realaudio"}, - {".ram", "audio/x-pn-realaudio"}, - {".rar", "application/x-rar-compressed"}, - {".ras", "image/x-cmu-raster"}, - {".rat", "application/rat-file"}, - {".rc", "text/plain"}, - {".rc2", "text/plain"}, - {".rct", "text/plain"}, - {".rdlc", "application/xml"}, - {".reg", "text/plain"}, - {".resx", "application/xml"}, - {".rf", "image/vnd.rn-realflash"}, - {".rgb", "image/x-rgb"}, - {".rgs", "text/plain"}, - {".rm", "application/vnd.rn-realmedia"}, - {".rmi", "audio/mid"}, - {".rmp", "application/vnd.rn-rn_music_package"}, - {".roff", "application/x-troff"}, - {".rpm", "audio/x-pn-realaudio-plugin"}, - {".rqy", "text/x-ms-rqy"}, - {".rtf", "application/rtf"}, - {".rtx", "text/richtext"}, - {".rvt", "application/octet-stream" }, - {".ruleset", "application/xml"}, - {".s", "text/plain"}, - {".safariextz", "application/x-safari-safariextz"}, - {".scd", "application/x-msschedule"}, - {".scr", "text/plain"}, - {".sct", "text/scriptlet"}, - {".sd2", "audio/x-sd2"}, - {".sdp", "application/sdp"}, - {".sea", "application/octet-stream"}, - {".searchConnector-ms", "application/windows-search-connector+xml"}, - {".setpay", "application/set-payment-initiation"}, - {".setreg", "application/set-registration-initiation"}, - {".settings", "application/xml"}, - {".sgimb", "application/x-sgimb"}, - {".sgml", "text/sgml"}, - {".sh", "application/x-sh"}, - {".shar", "application/x-shar"}, - {".shtml", "text/html"}, - {".sit", "application/x-stuffit"}, - {".sitemap", "application/xml"}, - {".skin", "application/xml"}, - {".skp", "application/x-koan" }, - {".sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12"}, - {".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"}, - {".slk", "application/vnd.ms-excel"}, - {".sln", "text/plain"}, - {".slupkg-ms", "application/x-ms-license"}, - {".smd", "audio/x-smd"}, - {".smi", "application/octet-stream"}, - {".smx", "audio/x-smd"}, - {".smz", "audio/x-smd"}, - {".snd", "audio/basic"}, - {".snippet", "application/xml"}, - {".snp", "application/octet-stream"}, - {".sol", "text/plain"}, - {".sor", "text/plain"}, - {".spc", "application/x-pkcs7-certificates"}, - {".spl", "application/futuresplash"}, - {".spx", "audio/ogg"}, - {".src", "application/x-wais-source"}, - {".srf", "text/plain"}, - {".SSISDeploymentManifest", "text/xml"}, - {".ssm", "application/streamingmedia"}, - {".sst", "application/vnd.ms-pki.certstore"}, - {".stl", "application/vnd.ms-pki.stl"}, - {".sv4cpio", "application/x-sv4cpio"}, - {".sv4crc", "application/x-sv4crc"}, - {".svc", "application/xml"}, - {".svg", "image/svg+xml"}, - {".swf", "application/x-shockwave-flash"}, - {".step", "application/step"}, - {".stp", "application/step"}, - {".t", "application/x-troff"}, - {".tar", "application/x-tar"}, - {".tcl", "application/x-tcl"}, - {".testrunconfig", "application/xml"}, - {".testsettings", "application/xml"}, - {".tex", "application/x-tex"}, - {".texi", "application/x-texinfo"}, - {".texinfo", "application/x-texinfo"}, - {".tgz", "application/x-compressed"}, - {".thmx", "application/vnd.ms-officetheme"}, - {".thn", "application/octet-stream"}, - {".tif", "image/tiff"}, - {".tiff", "image/tiff"}, - {".tlh", "text/plain"}, - {".tli", "text/plain"}, - {".toc", "application/octet-stream"}, - {".tr", "application/x-troff"}, - {".trm", "application/x-msterminal"}, - {".trx", "application/xml"}, - {".ts", "video/vnd.dlna.mpeg-tts"}, - {".tsv", "text/tab-separated-values"}, - {".ttf", "application/font-sfnt"}, - {".tts", "video/vnd.dlna.mpeg-tts"}, - {".txt", "text/plain"}, - {".u32", "application/octet-stream"}, - {".uls", "text/iuls"}, - {".user", "text/plain"}, - {".ustar", "application/x-ustar"}, - {".vb", "text/plain"}, - {".vbdproj", "text/plain"}, - {".vbk", "video/mpeg"}, - {".vbproj", "text/plain"}, - {".vbs", "text/vbscript"}, - {".vcf", "text/x-vcard"}, - {".vcproj", "application/xml"}, - {".vcs", "text/plain"}, - {".vcxproj", "application/xml"}, - {".vddproj", "text/plain"}, - {".vdp", "text/plain"}, - {".vdproj", "text/plain"}, - {".vdx", "application/vnd.ms-visio.viewer"}, - {".vml", "text/xml"}, - {".vscontent", "application/xml"}, - {".vsct", "text/xml"}, - {".vsd", "application/vnd.visio"}, - {".vsi", "application/ms-vsi"}, - {".vsix", "application/vsix"}, - {".vsixlangpack", "text/xml"}, - {".vsixmanifest", "text/xml"}, - {".vsmdi", "application/xml"}, - {".vspscc", "text/plain"}, - {".vss", "application/vnd.visio"}, - {".vsscc", "text/plain"}, - {".vssettings", "text/xml"}, - {".vssscc", "text/plain"}, - {".vst", "application/vnd.visio"}, - {".vstemplate", "text/xml"}, - {".vsto", "application/x-ms-vsto"}, - {".vsw", "application/vnd.visio"}, - {".vsx", "application/vnd.visio"}, - {".vtt", "text/vtt"}, - {".vtx", "application/vnd.visio"}, - {".wasm", "application/wasm"}, - {".wav", "audio/wav"}, - {".wave", "audio/wav"}, - {".wax", "audio/x-ms-wax"}, - {".wbk", "application/msword"}, - {".wbmp", "image/vnd.wap.wbmp"}, - {".wcm", "application/vnd.ms-works"}, - {".wdb", "application/vnd.ms-works"}, - {".wdp", "image/vnd.ms-photo"}, - {".webarchive", "application/x-safari-webarchive"}, - {".webm", "video/webm"}, - {".webp", "image/webp"}, /* https://en.wikipedia.org/wiki/WebP */ - {".webtest", "application/xml"}, - {".wiq", "application/xml"}, - {".wiz", "application/msword"}, - {".wks", "application/vnd.ms-works"}, - {".WLMP", "application/wlmoviemaker"}, - {".wlpginstall", "application/x-wlpg-detect"}, - {".wlpginstall3", "application/x-wlpg3-detect"}, - {".wm", "video/x-ms-wm"}, - {".wma", "audio/x-ms-wma"}, - {".wmd", "application/x-ms-wmd"}, - {".wmf", "application/x-msmetafile"}, - {".wml", "text/vnd.wap.wml"}, - {".wmlc", "application/vnd.wap.wmlc"}, - {".wmls", "text/vnd.wap.wmlscript"}, - {".wmlsc", "application/vnd.wap.wmlscriptc"}, - {".wmp", "video/x-ms-wmp"}, - {".wmv", "video/x-ms-wmv"}, - {".wmx", "video/x-ms-wmx"}, - {".wmz", "application/x-ms-wmz"}, - {".woff", "application/font-woff"}, - {".woff2", "application/font-woff2"}, - {".wpl", "application/vnd.ms-wpl"}, - {".wps", "application/vnd.ms-works"}, - {".wri", "application/x-mswrite"}, - {".wrl", "x-world/x-vrml"}, - {".wrz", "x-world/x-vrml"}, - {".wsc", "text/scriptlet"}, - {".wsdl", "text/xml"}, - {".wvx", "video/x-ms-wvx"}, - {".x", "application/directx"}, - {".xaf", "x-world/x-vrml"}, - {".xaml", "application/xaml+xml"}, - {".xap", "application/x-silverlight-app"}, - {".xbap", "application/x-ms-xbap"}, - {".xbm", "image/x-xbitmap"}, - {".xdr", "text/plain"}, - {".xht", "application/xhtml+xml"}, - {".xhtml", "application/xhtml+xml"}, - {".xla", "application/vnd.ms-excel"}, - {".xlam", "application/vnd.ms-excel.addin.macroEnabled.12"}, - {".xlc", "application/vnd.ms-excel"}, - {".xld", "application/vnd.ms-excel"}, - {".xlk", "application/vnd.ms-excel"}, - {".xll", "application/vnd.ms-excel"}, - {".xlm", "application/vnd.ms-excel"}, - {".xls", "application/vnd.ms-excel"}, - {".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"}, - {".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"}, - {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, - {".xlt", "application/vnd.ms-excel"}, - {".xltm", "application/vnd.ms-excel.template.macroEnabled.12"}, - {".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"}, - {".xlw", "application/vnd.ms-excel"}, - {".xml", "text/xml"}, - {".xmp", "application/octet-stream" }, - {".xmta", "application/xml"}, - {".xof", "x-world/x-vrml"}, - {".XOML", "text/plain"}, - {".xpm", "image/x-xpixmap"}, - {".xps", "application/vnd.ms-xpsdocument"}, - {".xrm-ms", "text/xml"}, - {".xsc", "application/xml"}, - {".xsd", "text/xml"}, - {".xsf", "text/xml"}, - {".xsl", "text/xml"}, - {".xslt", "text/xml"}, - {".xsn", "application/octet-stream"}, - {".xss", "application/xml"}, - {".xspf", "application/xspf+xml"}, - {".xtp", "application/octet-stream"}, - {".xwd", "image/x-xwindowdump"}, - {".z", "application/x-compress"}, - {".zip", "application/zip"}, - - {"application/fsharp-script", ".fsx"}, - {"application/msaccess", ".adp"}, - {"application/msword", ".doc"}, - {"application/octet-stream", ".bin"}, - {"application/onenote", ".one"}, - {"application/postscript", ".eps"}, - {"application/step", ".step"}, - {"application/vnd.ms-excel", ".xls"}, - {"application/vnd.ms-powerpoint", ".ppt"}, - {"application/vnd.ms-works", ".wks"}, - {"application/vnd.visio", ".vsd"}, - {"application/x-director", ".dir"}, - {"application/x-shockwave-flash", ".swf"}, - {"application/x-x509-ca-cert", ".cer"}, - {"application/x-zip-compressed", ".zip"}, - {"application/xhtml+xml", ".xhtml"}, - {"application/xml", ".xml"}, // anomoly, .xml -> text/xml, but application/xml -> many thingss, but all are xml, so safest is .xml - {"audio/aac", ".AAC"}, - {"audio/aiff", ".aiff"}, - {"audio/basic", ".snd"}, - {"audio/mid", ".midi"}, - {"audio/wav", ".wav"}, - {"audio/x-m4a", ".m4a"}, - {"audio/x-mpegurl", ".m3u"}, - {"audio/x-pn-realaudio", ".ra"}, - {"audio/x-smd", ".smd"}, - {"image/bmp", ".bmp"}, - {"image/jpeg", ".jpg"}, - {"image/pict", ".pic"}, - {"image/png", ".png"}, //Defined in [RFC-2045], [RFC-2048] - {"image/x-png", ".png"}, //See https://www.w3.org/TR/PNG/#A-Media-type :"It is recommended that implementations also recognize the media type "image/x-png"." - {"image/tiff", ".tiff"}, - {"image/x-macpaint", ".mac"}, - {"image/x-quicktime", ".qti"}, - {"message/rfc822", ".eml"}, - {"text/html", ".html"}, - {"text/plain", ".txt"}, - {"text/scriptlet", ".wsc"}, - {"text/xml", ".xml"}, - {"video/3gpp", ".3gp"}, - {"video/3gpp2", ".3gp2"}, - {"video/mp4", ".mp4"}, - {"video/mpeg", ".mpg"}, - {"video/quicktime", ".mov"}, - {"video/vnd.dlna.mpeg-tts", ".m2t"}, - {"video/x-dv", ".dv"}, - {"video/x-la-asf", ".lsf"}, - {"video/x-ms-asf", ".asf"}, - {"x-world/x-vrml", ".xof"}, - - #endregion - - }; - - var cache = mappings.ToList(); // need ToList() to avoid modifying while still enumerating - - foreach (var mapping in cache) - { - if (!mappings.ContainsKey(mapping.Value)) - { - mappings.Add(mapping.Value, mapping.Key); - } - } - - return mappings; - } - - public static string GetMimeType(string extension) - { - if (extension == null) - { - throw new ArgumentNullException("extension"); - } - - if (!extension.StartsWith(".")) - { - extension = "." + extension; - } - - string mime; - - return _mappings.Value.TryGetValue(extension, out mime) ? mime : "application/octet-stream"; - } - - public static string GetExtension(string mimeType) - { - return GetExtension(mimeType, true); - } - - public static string GetExtension(string mimeType, bool throwErrorIfNotFound) - { - if (mimeType == null) - { - throw new ArgumentNullException("mimeType"); - } - - if (mimeType.StartsWith(".")) - { - throw new ArgumentException("Requested mime type is not valid: " + mimeType); - } - - string extension; - - if (_mappings.Value.TryGetValue(mimeType, out extension)) - { - return extension; - } - if (throwErrorIfNotFound) - { - throw new ArgumentException("Requested mime type is not registered: " + mimeType); - } - else - { - return string.Empty; - } - } - } -} diff --git a/ln.http/message/TokenReader.cs b/ln.http/message/TokenReader.cs deleted file mode 100644 index ad5cefe..0000000 --- a/ln.http/message/TokenReader.cs +++ /dev/null @@ -1,68 +0,0 @@ -// /** -// * File: TokenReader.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.IO; -using System.Text; -using System.Linq; -namespace ln.http.message -{ - public class TokenReader : TextReader - { - public static char[] specialChars = new char[] { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=' }; - - public TextReader BaseReader { get; } - - public TokenReader(String text) - :this(new StringReader(text)) - {} - public TokenReader(TextReader baseReader) - { - BaseReader = baseReader; - } - - public override int Read() => BaseReader.Read(); - public override int Peek() => BaseReader.Peek(); - - public string ReadToken() - { - while ((BaseReader.Peek() != -1) && char.IsWhiteSpace((char)BaseReader.Peek())) - BaseReader.Read(); - - StringBuilder stringBuilder = new StringBuilder(); - int ch; - do - { - ch = BaseReader.Peek(); - - if ((ch <= ' ') || specialChars.Contains((char)ch)) - return stringBuilder.ToString(); - - stringBuilder.Append((char)BaseReader.Read()); - } while (ch != -1); - - return stringBuilder.ToString(); - } - - public string ReadQuotedString() - { - StringBuilder stringBuilder = new StringBuilder(); - - if (BaseReader.Read() != '"') - throw new FormatException("quoted string must start with \""); - - int ch; - while (((ch = BaseReader.Read()) != -1) && (ch != '"')) - stringBuilder.Append((char)ch); - - return stringBuilder.ToString(); - } - - } -} diff --git a/ln.http/message/parser/HTTP.cs b/ln.http/message/parser/HTTP.cs deleted file mode 100644 index 167ca49..0000000 --- a/ln.http/message/parser/HTTP.cs +++ /dev/null @@ -1,40 +0,0 @@ -// /** -// * File: HTTP.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.IO; -using System.Collections.Generic; -using ln.http.exceptions; -namespace ln.http.message.parser -{ - public static class HTTP - { - public static HeaderContainer ReadHeader(TextReader reader) - { - List headerLines = new List(); - string currentline = reader.ReadLine(); - while (!currentline.Equals(string.Empty)) - { - if (char.IsWhiteSpace(currentline[0])) - throw new BadRequestException(); - - headerLines.Add(currentline.Trim()); - - currentline = reader.ReadLine(); - } - - HeaderContainer headerContainer = new HeaderContainer(); - - foreach (string headerLine in headerLines) - headerContainer.Add(new Header(headerLine)); - - return headerContainer; - } - } -} diff --git a/ln.http/message/parser/MIME.cs b/ln.http/message/parser/MIME.cs deleted file mode 100644 index 19d314c..0000000 --- a/ln.http/message/parser/MIME.cs +++ /dev/null @@ -1,43 +0,0 @@ -// /** -// * File: MIME.cs -// * Author: haraldwolff -// * -// * This file and it's content is copyrighted by the Author and / or copyright holder. -// * Any use wihtout proper permission is illegal and may lead to legal actions. -// * -// * -// **/ -using System; -using System.IO; -using System.Collections.Generic; -namespace ln.http.message.parser -{ - public static class MIME - { - public static HeaderContainer ReadHeader(TextReader reader) - { - List headerLines = new List(); - string currentline = reader.ReadLine(); - while (!currentline.Equals(string.Empty)) - { - if (char.IsWhiteSpace(currentline[0])) - { - headerLines[headerLines.Count - 1] = headerLines[headerLines.Count - 1] + currentline; - } - else - { - headerLines.Add(currentline); - } - currentline = reader.ReadLine(); - } - - HeaderContainer headerContainer = new HeaderContainer(); - - foreach (string headerLine in headerLines) - headerContainer.Add(new Header(headerLine)); - - return headerContainer; - } - - } -} diff --git a/ln.http/router/FileRouter.cs b/ln.http/router/FileRouter.cs index 135ad8d..77915ff 100644 --- a/ln.http/router/FileRouter.cs +++ b/ln.http/router/FileRouter.cs @@ -8,7 +8,8 @@ // * // **/ using System.IO; -using ln.http.message; +using ln.http.mime; + namespace ln.http.router { public class FileRouter : IHttpRouter @@ -27,6 +28,7 @@ namespace ln.http.router { HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(FileName, FileMode.Open)); httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(FileName))); + return httpResponse; } diff --git a/ln.http/router/HttpRoutingContext.cs b/ln.http/router/HttpRoutingContext.cs index 31a26fe..7f7a263 100644 --- a/ln.http/router/HttpRoutingContext.cs +++ b/ln.http/router/HttpRoutingContext.cs @@ -8,7 +8,7 @@ namespace ln.http.router public string Path { get; set; } public string RoutedPath { get; set; } - public HttpRoutingContext(HttpRequest httpRequest) : this(httpRequest, httpRequest.URI.AbsolutePath) { } + public HttpRoutingContext(HttpRequest httpRequest) : this(httpRequest, httpRequest?.RequestUri?.AbsolutePath ?? "") { } public HttpRoutingContext(HttpRequest httpRequest, string path) { HttpRequest = httpRequest; @@ -48,6 +48,5 @@ namespace ln.http.router return true; } - } } diff --git a/ln.http/router/LoggingRouter.cs b/ln.http/router/LoggingRouter.cs index 825690e..fd0861a 100644 --- a/ln.http/router/LoggingRouter.cs +++ b/ln.http/router/LoggingRouter.cs @@ -48,8 +48,8 @@ namespace ln.http.router start, duration, response?.StatusCode.ToString() ?? "-", - httpRequest.Method, - httpRequest.RequestURL + httpRequest?.Method, + httpRequest?.RequestUri ); } diff --git a/ln.http/router/RouterTarget.cs b/ln.http/router/RouterTarget.cs index 1622a09..6be5089 100644 --- a/ln.http/router/RouterTarget.cs +++ b/ln.http/router/RouterTarget.cs @@ -25,19 +25,19 @@ namespace ln.http.router public virtual HttpResponse Dispatch(HttpRequest request) { - switch (request.Method.ToUpper()) + switch (request.Method) { - case "HEAD": + case HttpMethod.HEAD: return HEAD(request); - case "GET": + case HttpMethod.GET: return GET(request); - case "PROPFIND": + case HttpMethod.PROPFIND: return PROPFIND(request); - case "POST": + case HttpMethod.POST: return POST(request); - case "PUT": + case HttpMethod.PUT: return PUT(request); - case "DELETE": + case HttpMethod.DELETE: return DELETE(request); default: throw new MethodNotAllowedException(); diff --git a/ln.http/router/StaticRouter.cs b/ln.http/router/StaticRouter.cs index 01ab456..3bb1710 100644 --- a/ln.http/router/StaticRouter.cs +++ b/ln.http/router/StaticRouter.cs @@ -9,8 +9,9 @@ // **/ using System; using System.IO; -using ln.http.message; using System.Collections.Generic; +using ln.http.mime; + namespace ln.http.router { public class StaticRouter : IHttpRouter @@ -36,7 +37,7 @@ namespace ln.http.router public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest) { - string finalPath = Path.Combine(RootPath, routingContext.Path.Substring(1)); + string finalPath = routingContext.Path.Length > 0 ? Path.Combine(RootPath, routingContext.Path.Substring(1)) : "."; if (Directory.Exists(finalPath)) { diff --git a/ln.http/router/VirtualHostRouter.cs b/ln.http/router/VirtualHostRouter.cs index 127f69a..52b935f 100644 --- a/ln.http/router/VirtualHostRouter.cs +++ b/ln.http/router/VirtualHostRouter.cs @@ -1,4 +1,4 @@ -using ln.http.exceptions; +using ln.http.exceptions; using System.Collections.Generic; namespace ln.http.router @@ -28,21 +28,21 @@ namespace ln.http.router } public VirtualHostRouter(VirtualHostRouter source) : this(source.virtualHosts) { } - - public void Add(string hostname,IHttpRouter router) => virtualHosts.Add(hostname, router); - public void Remove(string hostname) => virtualHosts.Remove(hostname); - public bool Contains(string hostname) => virtualHosts.ContainsKey(hostname); - - public bool TryGetValue(string hostname, out IHttpRouter router) => virtualHosts.TryGetValue(hostname, out router); - - public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest) - { - if (virtualHosts.TryGetValue(httpRequest.Hostname, out IHttpRouter virtualHost)) + + public void Add(string hostname,IHttpRouter router) => virtualHosts.Add(hostname, router); + public void Remove(string hostname) => virtualHosts.Remove(hostname); + public bool Contains(string hostname) => virtualHosts.ContainsKey(hostname); + + public bool TryGetValue(string hostname, out IHttpRouter router) => virtualHosts.TryGetValue(hostname, out router); + + public HttpResponse Route(HttpRoutingContext routingContext, HttpRequest httpRequest) + { + if (virtualHosts.TryGetValue(httpRequest.Host, out IHttpRouter virtualHost)) return virtualHost.Route(routingContext, httpRequest); if (DefaultRoute != null) return DefaultRoute.Route(routingContext, httpRequest); - throw new HttpException(410, string.Format("Gone. Hostname {0} not found on this server.", httpRequest.Hostname)); + throw new HttpException(410, string.Format("Gone. Hostname {0} not found on this server.", httpRequest.Host)); } } } diff --git a/ln.http/session/Session.cs b/ln.http/session/Session.cs index 90bdfe1..67eb0c9 100644 --- a/ln.http/session/Session.cs +++ b/ln.http/session/Session.cs @@ -1,4 +1,5 @@ -using System; +/* +using System; using System.Collections.Generic; using System.Linq; @@ -67,3 +68,4 @@ namespace ln.http.session } } } +*/ diff --git a/ln.http/session/SessionCache.cs b/ln.http/session/SessionCache.cs index 79cdca6..481f4de 100644 --- a/ln.http/session/SessionCache.cs +++ b/ln.http/session/SessionCache.cs @@ -1,4 +1,5 @@ -using System; +/* +using System; using System.Collections.Generic; namespace ln.http.session { @@ -18,7 +19,7 @@ namespace ln.http.session /* * Create a new Session instance * - */ + #1# public virtual Session CreateSession() { return new Session(); @@ -27,7 +28,7 @@ namespace ln.http.session /* * Find and return SessionID from given HttpRequest * - */ + #1# public virtual Guid FindSessionID(HttpRequest httpRequest) { if (httpRequest.ContainsCookie("SID_LN")) @@ -40,7 +41,7 @@ namespace ln.http.session /* * Apply SessionID of the given Session to the given Response * - */ + #1# public virtual void ApplySessionID(HttpResponse httpResponse,Session session) { HttpCookie sessionCookie = new HttpCookie("SID_LN",session.SessionID.ToString()); @@ -73,3 +74,4 @@ namespace ln.http.session } } +*/ diff --git a/ln.http/websocket/WebSocket.cs b/ln.http/websocket/WebSocket.cs index 4585424..1823d72 100644 --- a/ln.http/websocket/WebSocket.cs +++ b/ln.http/websocket/WebSocket.cs @@ -35,7 +35,7 @@ namespace ln.http.websocket public abstract class WebSocket { - public HTTPServer HTTPServer => HttpRequest.HTTPServer; + public HTTPServer HTTPServer => HttpRequest.Server; public HttpRequest HttpRequest { get; } public Stream Stream { get; } @@ -44,7 +44,7 @@ namespace ln.http.websocket public WebSocket(HttpRequest httpRequest) { HttpRequest = httpRequest; - Stream = httpRequest.GetConnectionStream(); + Stream = httpRequest.ConnectionStream; if ((!httpRequest.GetRequestHeader("upgrade", "").Contains("websocket")) && (!httpRequest.GetRequestHeader("connection", "").Contains("Upgrade"))) throw new HttpException(400, "This resource is a websocket endpoint only"); @@ -66,8 +66,7 @@ namespace ln.http.websocket Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(acceptKey))) ); - HTTPServer.SendResponse(Stream, httpRequest, httpResponse); - //HTTPServerConnection.Current.Value.AbortRequested += (connection) => Close(); + httpResponse.WriteTo(Stream); State = WebSocketState.OPEN; } diff --git a/ln.http/websocket/WebSocketResponse.cs b/ln.http/websocket/WebSocketResponse.cs index 1d6575b..569a2d4 100644 --- a/ln.http/websocket/WebSocketResponse.cs +++ b/ln.http/websocket/WebSocketResponse.cs @@ -154,7 +154,7 @@ namespace ln.http.websocket } - public override void SendResponse(Stream stream, HttpRequest httpRequest) + public void SendResponse(Stream stream, HttpRequest httpRequest) { lock (this) { @@ -180,11 +180,10 @@ namespace ln.http.websocket Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(acceptKey))) ); - HTTPServer.SendResponse(Stream, httpRequest, httpResponse); - //HTTPServerConnection.Current.Value.AbortRequested += (connection) => Close(); + base.WriteTo(Stream); State = WebSocketState.OPEN; } - Run(); + Run(); } } }