Compare commits
2 commits
242982ff0b
...
57293135a2
Author | SHA1 | Date | |
---|---|---|---|
|
57293135a2 | ||
|
a0db75bfdd |
4 changed files with 40 additions and 17 deletions
|
@ -60,6 +60,11 @@ public sealed class HttpServer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan Timeout = TimeSpan.FromSeconds(20);
|
public TimeSpan Timeout = TimeSpan.FromSeconds(20);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum time a websocket may be inactive before it is presumed dead and closed.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan TimeoutWS = TimeSpan.FromSeconds(60);
|
||||||
|
|
||||||
readonly Dictionary<IPAddress, int> IPCounts = new Dictionary<IPAddress, int>();
|
readonly Dictionary<IPAddress, int> IPCounts = new Dictionary<IPAddress, int>();
|
||||||
|
|
||||||
readonly SemaphoreSlim IPCountsLock = new SemaphoreSlim(1, 1);
|
readonly SemaphoreSlim IPCountsLock = new SemaphoreSlim(1, 1);
|
||||||
|
@ -165,6 +170,9 @@ public sealed class HttpServer
|
||||||
|
|
||||||
if (response is SwitchingProtocols swp)
|
if (response is SwitchingProtocols swp)
|
||||||
{
|
{
|
||||||
|
httpStream.Timeout = TimeoutWS;
|
||||||
|
httpStream.KeepAlive();
|
||||||
|
|
||||||
//Create and run websocket
|
//Create and run websocket
|
||||||
WebsocketRemote ws = new WebsocketRemote(req, clientInfo, httpStream, swp.Fields.WebSocketProtocol);
|
WebsocketRemote ws = new WebsocketRemote(req, clientInfo, httpStream, swp.Fields.WebSocketProtocol);
|
||||||
CloseStatus closeStatus = await swp.Callback(ws);
|
CloseStatus closeStatus = await swp.Callback(ws);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace Uwaa.HTTP;
|
namespace Uwaa.HTTP;
|
||||||
|
|
||||||
|
@ -28,19 +26,27 @@ class HttpStream : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan Timeout;
|
public TimeSpan Timeout;
|
||||||
|
|
||||||
|
internal readonly CancellationTokenSource CancelSrc = new CancellationTokenSource();
|
||||||
|
|
||||||
public HttpStream(Stream stream, TimeSpan timeout) : base()
|
public HttpStream(Stream stream, TimeSpan timeout) : base()
|
||||||
{
|
{
|
||||||
Stream = stream;
|
Stream = stream;
|
||||||
Timeout = timeout;
|
Timeout = timeout;
|
||||||
Buffer = new BufferedStream(stream);
|
Buffer = new BufferedStream(stream);
|
||||||
Decoder = Encoding.ASCII.GetDecoder();
|
Decoder = Encoding.ASCII.GetDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the timeout timer.
|
||||||
|
/// </summary>
|
||||||
|
public void KeepAlive()
|
||||||
|
{
|
||||||
|
CancelSrc.CancelAfter(Timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<string> ReadLine()
|
public async ValueTask<string> ReadLine()
|
||||||
{
|
{
|
||||||
CancellationTokenSource cancelSrc = new CancellationTokenSource();
|
CancelSrc.CancelAfter(Timeout);
|
||||||
cancelSrc.CancelAfter(Timeout);
|
|
||||||
|
|
||||||
const int maxChars = 4096;
|
const int maxChars = 4096;
|
||||||
byte[] dataBuffer = ArrayPool<byte>.Shared.Rent(1);
|
byte[] dataBuffer = ArrayPool<byte>.Shared.Rent(1);
|
||||||
|
@ -50,7 +56,7 @@ class HttpStream : IDisposable
|
||||||
int charBufferIndex = 0;
|
int charBufferIndex = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (await Buffer.ReadAsync(dataBuffer.AsMemory(0, 1), cancelSrc.Token) == 0)
|
if (await Stream.ReadAsync(dataBuffer.AsMemory(0, 1), CancelSrc.Token) == 0)
|
||||||
if (charBufferIndex == 0)
|
if (charBufferIndex == 0)
|
||||||
throw new SocketException((int)SocketError.ConnectionReset);
|
throw new SocketException((int)SocketError.ConnectionReset);
|
||||||
else
|
else
|
||||||
|
@ -87,15 +93,14 @@ class HttpStream : IDisposable
|
||||||
|
|
||||||
public async ValueTask<int> Read(Memory<byte> buffer)
|
public async ValueTask<int> Read(Memory<byte> buffer)
|
||||||
{
|
{
|
||||||
CancellationTokenSource cancelSrc = new CancellationTokenSource();
|
CancelSrc.CancelAfter(Timeout);
|
||||||
cancelSrc.CancelAfter(Timeout);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (index < buffer.Length)
|
while (index < buffer.Length)
|
||||||
{
|
{
|
||||||
int count = await Buffer.ReadAsync(buffer[index..], cancelSrc.Token);
|
int count = await Stream.ReadAsync(buffer[index..], CancelSrc.Token);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -134,11 +139,10 @@ class HttpStream : IDisposable
|
||||||
|
|
||||||
public ValueTask Write(ReadOnlyMemory<byte> bytes)
|
public ValueTask Write(ReadOnlyMemory<byte> bytes)
|
||||||
{
|
{
|
||||||
CancellationTokenSource cancelSrc = new CancellationTokenSource();
|
CancelSrc.CancelAfter(Timeout);
|
||||||
cancelSrc.CancelAfter(Timeout);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Buffer.WriteAsync(bytes, cancelSrc.Token);
|
return Buffer.WriteAsync(bytes, CancelSrc.Token);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
|
@ -151,12 +155,11 @@ class HttpStream : IDisposable
|
||||||
|
|
||||||
public async Task Flush()
|
public async Task Flush()
|
||||||
{
|
{
|
||||||
CancellationTokenSource cancelSrc = new CancellationTokenSource();
|
CancelSrc.CancelAfter(Timeout);
|
||||||
cancelSrc.CancelAfter(Timeout);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Buffer.FlushAsync(cancelSrc.Token);
|
await Buffer.FlushAsync(CancelSrc.Token);
|
||||||
await Stream.FlushAsync(cancelSrc.Token);
|
await Stream.FlushAsync(CancelSrc.Token);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,5 +12,8 @@ public enum CloseStatus : ushort
|
||||||
PolicyViolation = 1008,
|
PolicyViolation = 1008,
|
||||||
MessageTooBig = 1009,
|
MessageTooBig = 1009,
|
||||||
MandatoryExtension = 1010,
|
MandatoryExtension = 1010,
|
||||||
InternalServerError = 1011
|
InternalServerError = 1011,
|
||||||
|
ServiceRestart = 1012,
|
||||||
|
TryAgainLater = 1013,
|
||||||
|
BadGateway = 1014,
|
||||||
}
|
}
|
|
@ -14,6 +14,15 @@ public class Websocket
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string? SubProtocol;
|
public readonly string? SubProtocol;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum time the websocket may be inactive before it is presumed dead and closed.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan Timeout
|
||||||
|
{
|
||||||
|
get => Stream.Timeout;
|
||||||
|
set => Stream.Timeout = value;
|
||||||
|
}
|
||||||
|
|
||||||
internal readonly HttpStream Stream;
|
internal readonly HttpStream Stream;
|
||||||
|
|
||||||
readonly List<byte> finalPayload = new List<byte>();
|
readonly List<byte> finalPayload = new List<byte>();
|
||||||
|
|
Loading…
Reference in a new issue