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();
}
}
}