master
Harald Wolff 2020-02-04 08:59:58 +01:00
parent f06af9d2c9
commit 92024abb13
21 changed files with 848 additions and 33 deletions

View File

@ -8,6 +8,8 @@ using ln.types.net;
using System.Globalization;
using ln.http.exceptions;
using System.Threading;
using ln.types;
using ln.http.router;
namespace ln.http
@ -166,6 +168,9 @@ namespace ln.http
{
keepAlive = false;
}
response?.ContentStream?.Dispose();
} while (keepAlive);
}
catch (Exception e)
@ -183,7 +188,6 @@ namespace ln.http
}
HttpRequest.ClearCurrent();
connection.GetStream().Close();
} finally
{
@ -197,5 +201,45 @@ namespace ln.http
Logger.Log(LogLevel.INFO, "{0} {1} {2} {3}",startTime.ToString("yyyyMMdd-HH:mm:ss"),duration.ToString(CultureInfo.InvariantCulture),httpRequest.Hostname,httpRequest.RequestURL);
}
public static void StartSimpleServer(string[] arguments)
{
ArgumentContainer argumentContainer = new ArgumentContainer(new Argument[]
{
new Argument('p',"port",8080),
new Argument('l',"listen","127.0.0.1"),
new Argument('c', "catch",null)
});
argumentContainer.Parse(arguments);
SimpleRouter router = new SimpleRouter();
router.AddSimpleRoute("/*", new RouterTarget((request) =>
{
HttpResponse response = new HttpResponse(request);
response.StatusCode = 404;
response.SetHeader("content-type", "text/plain");
response.ContentWriter.WriteLine("404 Not Found");
response.ContentWriter.Flush();
return response;
}), -100);
foreach (String path in argumentContainer.AdditionalArguments)
{
StaticRouter staticRouter = new StaticRouter(path);
staticRouter.AddIndex("index.html");
staticRouter.AddIndex("index.htm");
router.AddSimpleRoute("/*", staticRouter);
}
if (argumentContainer['c'].IsSet)
router.AddSimpleRoute("/*", new RouterTarget((request) => router.Route(argumentContainer['c'].Value,request)),0);
HTTPServer server = new HTTPServer(new Endpoint(IPv6.Parse(argumentContainer['l'].Value),argumentContainer['p'].IntegerValue),
new LoggingRouter(router));
server.Start();
}
}
}

View File

@ -4,6 +4,9 @@ using System.Text;
using System.Collections.Generic;
using System.Net;
using ln.types.net;
using ln.http.message;
using ln.http.io;
using ln.http.message.parser;
namespace ln.http
{
@ -20,11 +23,13 @@ namespace ln.http
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<string, string> Headers { get; } = new Dictionary<string, string>();
//public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>();
public bool Valid { get; private set; } = false;
@ -40,19 +45,18 @@ namespace ln.http
public void Read()
{
ReadRequestHead();
UnbufferedStreamReader reader = new UnbufferedStreamReader(Stream);
string requestLine = reader.ReadLine();
string[] requestTokens = requestLine.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
if (blen == 0)
return;
if (requestTokens.Length != 3)
throw new FormatException("request line malformed");
Method = ReadToken();
SkipWhiteSpace();
URL = ReadToken();
SkipWhiteSpace();
Protocol = ReadToken();
ReadLine();
Method = requestTokens[0];
URL = requestTokens[1];
Protocol = requestTokens[2];
ReadHeaders();
Headers = HTTP.ReadHeader(reader);
Valid = true;
}
@ -170,16 +174,16 @@ namespace ln.http
return value.Trim();
}
public void ReadHeaders()
{
while (bptr < hlen)
{
String name = ReadHeaderName();
String value = ReadHeaderValue();
//public void ReadHeaders()
//{
// while (bptr < hlen)
// {
// String name = ReadHeaderName();
// String value = ReadHeaderValue();
Headers.Add(name, value);
}
}
// Headers.Add(name, value);
// }
//}
public int ReadRequestBody(byte[] dst,int offset,int length)
{

View File

@ -6,6 +6,7 @@ using ln.http.exceptions;
using ln.types.net;
using System.Threading;
using ln.http.session;
using ln.http.message;
namespace ln.http
{
@ -14,7 +15,8 @@ namespace ln.http
static ThreadLocal<HttpRequest> current = new ThreadLocal<HttpRequest>();
static public HttpRequest Current => current.Value;
Dictionary<String, String> requestHeaders;
//Dictionary<String, String> requestHeaders;
HeaderContainer requestHeaders;
Dictionary<String, String> requestCookies;
Dictionary<string, String> requestParameters;
@ -38,6 +40,7 @@ namespace ln.http
public Session Session { get; set; }
public HttpUser CurrentUser => Session.CurrentUser;
public HeaderContainer RequestHeaders => requestHeaders;
public MemoryStream ContentStream { get; }
public TextReader ContentReader
@ -70,7 +73,8 @@ namespace ln.http
Protocol = httpReader.Protocol;
RequestURL = httpReader.URL;
requestHeaders = new Dictionary<string, string>(httpReader.Headers);
//requestHeaders = new Dictionary<string, string>(httpReader.Headers);
requestHeaders = httpReader.Headers;
requestCookies = new Dictionary<string, string>();
requestParameters = new Dictionary<string, string>();
@ -156,7 +160,7 @@ namespace ln.http
name = name.ToUpper();
if (requestHeaders.ContainsKey(name))
return requestHeaders[name];
return requestHeaders[name].Value;
return def;
}

View File

@ -0,0 +1,20 @@
// /**
// * File: BadRequest.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.exceptions
{
public class BadRequestException: HttpException
{
public BadRequestException()
:base(400,"Bad Request")
{
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace ln.http.exceptions
{
public class DisposeConnectionException : Exception
{
public DisposeConnectionException()
{
}
}
}

View File

@ -0,0 +1,68 @@
// /**
// * File: UnbufferedStreamreader.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;
namespace ln.http.io
{
public class UnbufferedStreamReader : TextReader
{
public Stream Stream { get; }
public UnbufferedStreamReader(Stream stream)
{
Stream = stream;
}
public override int Read() => Stream.ReadByte();
public override string ReadLine()
{
StringBuilder stringBuilder = new StringBuilder();
char ch;
while ((ch = (char)Stream.ReadByte()) != -1)
{
if (ch == '\r')
{
ch = (char)Stream.ReadByte();
if (ch == '\n')
return stringBuilder.ToString();
stringBuilder.Append('\r');
}
stringBuilder.Append(ch);
}
if ((ch == -1) && (stringBuilder.Length == 0))
return null;
return stringBuilder.ToString();
}
public string ReadToken()
{
StringBuilder stringBuilder = new StringBuilder();
char ch = (char)Stream.ReadByte();
while (char.IsWhiteSpace(ch))
ch = (char)Stream.ReadByte();
while (!char.IsWhiteSpace(ch))
{
stringBuilder.Append(ch);
ch = (char)Stream.ReadByte();
}
return stringBuilder.ToString();
}
}
}

View File

@ -68,13 +68,23 @@
<Compile Include="IHTTPResource.cs" />
<Compile Include="router\VirtualHostRouter.cs" />
<Compile Include="IHttpRouter.cs" />
<Compile Include="mime\MimeTypeMap.cs" />
<Compile Include="message\MimeTypeMap.cs" />
<Compile Include="router\RouterTarget.cs" />
<Compile Include="router\SimpleRouter.cs" />
<Compile Include="router\StaticRouter.cs" />
<Compile Include="router\FileRouter.cs" />
<Compile Include="router\LoggingRouter.cs" />
<Compile Include="exceptions\MethodNotAllowedException.cs" />
<Compile Include="router\WebsocketRouter.cs" />
<Compile Include="exceptions\DisposeConnectionException.cs" />
<Compile Include="message\Message.cs" />
<Compile Include="message\Header.cs" />
<Compile Include="message\HeaderContainer.cs" />
<Compile Include="io\UnbufferedStreamreader.cs" />
<Compile Include="message\TokenReader.cs" />
<Compile Include="message\parser\MIME.cs" />
<Compile Include="message\parser\HTTP.cs" />
<Compile Include="exceptions\BadRequestException.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="exceptions\" />
@ -85,7 +95,9 @@
<Folder Include="cert\" />
<Folder Include="listener\" />
<Folder Include="router\" />
<Folder Include="mime\" />
<Folder Include="message\" />
<Folder Include="io\" />
<Folder Include="message\parser\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ln.logging\ln.logging.csproj">

View File

@ -0,0 +1,9 @@
using System;
namespace ln.http.simple
{
class MainClass
{
public static void Main(string[] args) => HTTPServer.StartSimpleServer(args);
}
}

View File

@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("ln.http.simple")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{516D661A-2DFE-4AC7-A32F-28CCF5F6A5F1}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ln.http.simple</RootNamespace>
<AssemblyName>ln.http.simple</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ln.http.csproj">
<Project>{CEEEEB41-3059-46A2-A871-2ADE22C013D9}</Project>
<Name>ln.http</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

159
message/Header.cs 100644
View File

@ -0,0 +1,159 @@
// /**
// * 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<string, string> 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<string, string>();
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);
}
}

View File

@ -0,0 +1,76 @@
// /**
// * 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<string, Header> headers = new Dictionary<string, Header>();
public HeaderContainer()
{
}
public HeaderContainer(Stream stream):this(new UnbufferedStreamReader(stream))
{
}
public HeaderContainer(TextReader reader)
{
List<String> headerLines = new List<string>();
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<string> Keys => headers.Keys;
}
}

153
message/Message.cs 100644
View File

@ -0,0 +1,153 @@
// /**
// * 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.types;
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<Message> 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<Message>();
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<int> offsets = new List<int>();
List<int> validated = new List<int>();
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<Message> 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();
}
}
}

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
namespace ln.http.mime
namespace ln.http.message
{
public static class MimeTypeMap
{

View File

@ -0,0 +1,68 @@
// /**
// * 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();
}
}
}

View File

@ -0,0 +1,40 @@
// /**
// * 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<String> headerLines = new List<string>();
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;
}
}
}

View File

@ -0,0 +1,43 @@
// /**
// * 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<String> headerLines = new List<string>();
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;
}
}
}

View File

@ -8,7 +8,7 @@
// *
// **/
using System.IO;
using ln.http.mime;
using ln.http.message;
namespace ln.http.router
{
public class FileRouter : IHttpRouter

View File

@ -9,7 +9,7 @@
// **/
using System;
using System.IO;
using ln.http.mime;
using ln.http.message;
using System.Collections.Generic;
namespace ln.http.router
{
@ -53,9 +53,12 @@ namespace ln.http.router
if (File.Exists(finalPath))
{
HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(finalPath, FileMode.Open));
httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(finalPath)));
return httpResponse;
lock (this)
{
HttpResponse httpResponse = new HttpResponse(httpRequest, new FileStream(finalPath, FileMode.Open));
httpResponse.SetHeader("content-type", MimeTypeMap.GetMimeType(Path.GetExtension(finalPath)));
return httpResponse;
}
}
return null;
}

View File

@ -0,0 +1,32 @@
using System;
using ln.http.websocket;
using ln.http.exceptions;
using ln.logging;
namespace ln.http.router
{
public class WebsocketRouter : IHttpRouter
{
Func<HttpRequest, WebSocket> createWebsocket;
public WebsocketRouter(Func<HttpRequest, WebSocket> createWebsocketDelegate)
{
createWebsocket = createWebsocketDelegate;
}
public WebSocket CreateWebSocket(HttpRequest request) => createWebsocket(request);
public HttpResponse Route(string path, HttpRequest httpRequest)
{
WebSocket websocket = CreateWebSocket(httpRequest);
try
{
websocket.Run();
}
catch (Exception e)
{
Logging.Log(e);
}
throw new DisposeConnectionException();
}
}
}

View File

@ -33,7 +33,6 @@ namespace ln.http.websocket
public delegate void WebSocketEventDelegate(WebSocket sender,WebSocketEventArgs e);
public abstract class WebSocket
{
public HTTPServer HTTPServer => HttpRequest.HTTPServer;