Initial Commit
commit
81b547cdce
|
@ -0,0 +1,5 @@
|
|||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
|
@ -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
|
|
@ -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>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<LangVersion>9</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -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
|
Loading…
Reference in New Issue