Initial Commit

master
Harald Wolff 2021-12-15 10:59:16 +01:00
commit 81b547cdce
13 changed files with 492 additions and 0 deletions

5
.gitignore vendored 100644
View File

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

View File

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/.idea.ln.protocols.helper.iml
/contentModel.xml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

197
HeaderContainer.cs 100644
View File

@ -0,0 +1,197 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace ln.protocols.helper
{
public class HeaderContainer : IEnumerable<Header>
{
private Dictionary<string, Header> _headers = new Dictionary<string, Header>();
public HeaderContainer()
{
}
public HeaderContainer(Stream stream)
{
Read(stream);
}
public void Read(Stream stream)
{
string headerName = null;
string headerLine;
while (!String.Empty.Equals(headerLine = stream.ReadLine()))
{
int colon = headerLine.IndexOf(':', StringComparison.InvariantCulture);
if (char.IsWhiteSpace(headerLine[0]))
{
if (headerName is string)
Add(headerName, " " + headerLine.Substring(1).Trim());
else
throw new FormatException("expected header name");
}
else if (colon > 0)
{
headerName = headerLine.Substring(0, colon);
Add(headerName, headerLine.Substring(colon + 1));
}
}
}
public string this[string headerName]
{
get => Get(headerName);
set => Set(headerName, value);
}
bool TryGetHeader(string headerName, out Header header) =>
_headers.TryGetValue(headerName.ToLower(), out header);
public bool TryGetValue(string headerName, out string headerValue)
{
if (_headers.TryGetValue(headerName.ToLower(), out Header header))
{
headerValue = header.Value;
return true;
}
headerValue = null;
return false;
}
public bool Contains(string headerName) => _headers.ContainsKey(headerName.ToLower());
public void Add(string headerName, string headerValue)
{
string lowerHeaderName = headerName.ToLower();
if (_headers.TryGetValue(lowerHeaderName, out Header header))
header.Value += " " + headerValue;
else
_headers.Add(lowerHeaderName, new Header(headerName, headerValue));
}
public void Remove(string headerName) => _headers.Remove(headerName.ToLower());
public void Clear() => _headers.Clear();
public void Set(string headerName, String headerValue)
{
string lowerHeaderName = headerName.ToLower();
if (!_headers.TryGetValue(lowerHeaderName, out Header header))
{
header = new Header(headerName, "");
_headers.Add(lowerHeaderName, header);
}
header.Value = headerValue;
}
public string Get(string headerName)
{
if (TryGetHeader(headerName, out Header header))
return header.Value;
return null;
}
public int GetInteger(string headerName)
{
return int.Parse(Get(headerName));
}
public int GetInteger(string headerName, int defaultValue)
{
if (TryGetValue(headerName, out string headerValue))
return int.Parse(headerValue);
return defaultValue;
}
public bool TryGetInteger(string headerName, out int value)
{
value = 0;
return TryGetValue(headerName, out string headerValue) && int.TryParse(headerValue, out value);
}
public float GetFloat(string headerName)
{
return float.Parse(Get(headerName));
}
public float GetFloat(string headerName, float defaultValue)
{
if (TryGetValue(headerName, out string headerValue))
return float.Parse(headerValue);
return defaultValue;
}
public bool TryGetFloat(string headerName, out float value)
{
value = 0;
return TryGetValue(headerName, out string headerValue) && float.TryParse(headerValue, out value);
}
public double GetDouble(string headerName)
{
return double.Parse(Get(headerName));
}
public double GetDouble(string headerName, double defaultValue)
{
if (TryGetValue(headerName, out string headerValue))
return double.Parse(headerValue);
return defaultValue;
}
public bool TryGetDouble(string headerName, out double value)
{
value = 0;
return TryGetValue(headerName, out string headerValue) && double.TryParse(headerValue, out value);
}
public IEnumerator<Header> GetEnumerator() => _headers.Values.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (var header in _headers)
sb.AppendFormat("{0}: {1}\r\n", header.Value.Name, header.Value.Value);
return sb.ToString();
}
}
public class Header
{
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
UpperName = value.ToUpper();
}
}
public string UpperName { get; private set; }
public string Value { get; set; }
public Header(string headerName)
{
Name = headerName;
Value = String.Empty;
}
public Header(string headerName, string headerValue)
{
Name = headerName;
Value = headerValue;
}
}
}

View File

@ -0,0 +1,40 @@
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using ln.rtp;
namespace ln.protocols.helper
{
public class HttpLikeProtocolReader
{
public static bool ReadRequest(Stream stream, Encoding encoding, out Request request)
{
request = new Request();
return ReadRequest(stream, encoding, request);
}
public static bool ReadRequest(Stream stream, Encoding encoding, Request request)
{
string requestLine = stream.ReadLine();
if (requestLine != null)
{
request.Method = requestLine.ReadToken(out requestLine);
request.RequestUri = requestLine.ReadToken(out requestLine);
request.Protocol = requestLine;
request.Headers.Clear();
request.Headers.Read(stream);
if (request.Headers.TryGetInteger("content-stream", out int contentLength) && (contentLength > 0))
{
request.ContentStream = new RequestContentStream(stream, contentLength);
}
if (stream is NetworkStream networkStream)
request.ClientAddress = ((IPEndPoint)networkStream.Socket.RemoteEndPoint).Address;
return true;
}
return false;
}
}
}

39
Request.cs 100644
View File

@ -0,0 +1,39 @@
using System;
using System.Net;
namespace ln.protocols.helper
{
public class Request : IDisposable
{
public virtual string Method { get; internal set; }
public virtual string Protocol { get; internal set; }
public virtual string RequestUri { get; internal set; }
public IPAddress ClientAddress { get; internal set; }
public HeaderContainer Headers { get; protected set; }
public RequestContentStream ContentStream { get; internal set; }
public Request()
{
Headers = new HeaderContainer();
}
protected Request(HeaderContainer headers)
{
Headers = headers;
}
public Request(string method, string requestUri, string protocol)
{
Method = method;
RequestUri = requestUri;
Protocol = protocol;
Headers = new HeaderContainer();
}
public void Dispose()
{
ContentStream?.Dispose();
}
}
}

View File

@ -0,0 +1,70 @@
using System;
using System.IO;
namespace ln.protocols.helper
{
public class RequestContentStream : Stream
{
public Stream BaseStream { get; }
private int contentLength;
private int position;
public RequestContentStream(Stream baseStream, int contentLength)
{
BaseStream = baseStream;
this.contentLength = contentLength;
}
public override int ReadByte()
{
int b = BaseStream.ReadByte();
if (b >= 0)
position++;
return b;
}
public override void Flush() { }
public override int Read(byte[] buffer, int offset, int count)
{
if (position == contentLength)
return 0;
if (position + count > contentLength)
count = contentLength - position;
int nread = BaseStream.Read(buffer, offset, count);
if (nread >= 0)
position += nread;
return nread;
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new System.NotImplementedException();
}
public override void SetLength(long value) => throw new System.NotImplementedException();
public override void Write(byte[] buffer, int offset, int count) => throw new System.NotImplementedException();
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => contentLength;
public override long Position
{
get => position;
set => throw new NotImplementedException();
}
protected override void Dispose(bool disposing)
{
if (position < contentLength)
{
byte[] buffer = new byte[4096];
while (Read(buffer, 0, buffer.Length) > 0) {}
}
}
}
}

View File

@ -0,0 +1,36 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace ln.protocols.helper
{
public static class StreamExtensions
{
public static string ReadLine(this Stream stream) => ReadLine(stream, Encoding.UTF8);
public static string ReadLine(this Stream stream, Encoding encoding)
{
if (!stream.CanRead)
return null;
byte[] line = new byte[1024];
int n = 0;
int ch;
while ((ch = stream.ReadByte()) != -1)
{
switch (ch)
{
case '\r':
break;
case '\n':
return encoding.GetString(line, 0, n);
default:
line[n++] = (byte)ch;
break;
}
}
if (n > 0)
return encoding.GetString(line, 0, n);
return null;
}
}
}

View File

@ -0,0 +1,50 @@
namespace ln.rtp
{
public static class StringExtensions
{
public static string ReadToken(this string line, out string rest)
{
int n = 0;
while (!char.IsWhiteSpace(line[n]))
n++;
int m = n;
while (char.IsWhiteSpace(line[m]))
m++;
string token = line.Substring(0, n);
rest = line.Substring(m);
return token;
}
public static string ReadToken(this string line, char delimiter)
{
int n = 0;
while (delimiter != line[n])
n++;
int m = n;
while (delimiter == line[m])
m++;
string token = line.Substring(0, n);
return token;
}
public static string ReadToken(this string line, char delimiter, out string rest)
{
int n = 0;
while (delimiter != line[n])
n++;
int m = n;
while (delimiter == line[m])
m++;
string token = line.Substring(0, n);
rest = line.Substring(m);
return token;
}
}
}

View File

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>9</LangVersion>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.protocols.helper", "ln.protocols.helper.csproj", "{64C5FB42-07AF-4B2E-8885-2758F19AD9B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{64C5FB42-07AF-4B2E-8885-2758F19AD9B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{64C5FB42-07AF-4B2E-8885-2758F19AD9B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64C5FB42-07AF-4B2E-8885-2758F19AD9B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64C5FB42-07AF-4B2E-8885-2758F19AD9B5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal