OF-DL/OF DL.Tests/Services/SimpleHttpServer.cs

84 lines
2.5 KiB
C#

using System.Net;
using System.Net.Sockets;
using System.Text;
namespace OF_DL.Tests.Services;
internal sealed class SimpleHttpServer : IDisposable
{
private readonly TcpListener _listener;
private readonly Task _handlerTask;
private readonly byte[] _responseBytes;
public SimpleHttpServer(string body, DateTime? lastModifiedUtc = null)
{
_listener = new TcpListener(IPAddress.Loopback, 0);
_listener.Start();
int port = ((IPEndPoint)_listener.LocalEndpoint).Port;
Url = new Uri($"http://127.0.0.1:{port}/");
_responseBytes = BuildResponse(body, lastModifiedUtc);
_handlerTask = Task.Run(HandleOnceAsync);
}
public Uri Url { get; }
public Task Completion => _handlerTask;
public void Dispose()
{
_listener.Stop();
try
{
_handlerTask.Wait(TimeSpan.FromSeconds(1));
}
catch
{
// ignored
}
}
private async Task HandleOnceAsync()
{
using TcpClient client = await _listener.AcceptTcpClientAsync();
await using NetworkStream stream = client.GetStream();
await ReadHeadersAsync(stream);
await stream.WriteAsync(_responseBytes);
}
private static async Task ReadHeadersAsync(NetworkStream stream)
{
byte[] buffer = new byte[1024];
int read;
string data = "";
while ((read = await stream.ReadAsync(buffer)) > 0)
{
data += Encoding.ASCII.GetString(buffer, 0, read);
if (data.Contains("\r\n\r\n", StringComparison.Ordinal))
{
break;
}
}
}
private static byte[] BuildResponse(string body, DateTime? lastModifiedUtc)
{
byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
StringBuilder header = new();
header.Append("HTTP/1.1 200 OK\r\n");
header.Append("Content-Type: application/xml\r\n");
header.Append($"Content-Length: {bodyBytes.Length}\r\n");
if (lastModifiedUtc.HasValue)
{
header.Append($"Last-Modified: {lastModifiedUtc.Value.ToUniversalTime():R}\r\n");
}
header.Append("Connection: close\r\n\r\n");
byte[] headerBytes = Encoding.ASCII.GetBytes(header.ToString());
byte[] response = new byte[headerBytes.Length + bodyBytes.Length];
Buffer.BlockCopy(headerBytes, 0, response, 0, headerBytes.Length);
Buffer.BlockCopy(bodyBytes, 0, response, headerBytes.Length, bodyBytes.Length);
return response;
}
}