84 lines
2.5 KiB
C#
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;
|
|
}
|
|
}
|