// Copyright 2026 Kingsrook, LLC
// SPDX-License-Identifier: Apache-2.0
using System.Net;
using System.Threading.Channels;
namespace Printing.NativeAuth;
/// Receives the actual HTTPS-proxied callback only inside this test network.
internal sealed class CallbackReceiver : IDisposable
{
private readonly HttpListener _listener = new();
private readonly Channel _callbacks = Channel.CreateBounded(1);
private readonly Uri _callback;
internal CallbackReceiver(Uri callback)
{
_callback = callback;
_listener.Prefixes.Add("http://+:8088/");
_listener.Start();
_ = ReceiveAsync();
}
private async Task ReceiveAsync()
{
try
{
while(_listener.IsListening)
{
HttpListenerContext context = await _listener.GetContextAsync();
Uri? request = context.Request.Url;
bool valid = request is not null && request.AbsolutePath == _callback.AbsolutePath
&& context.Request.Headers["Host"] == _callback.Authority
&& context.Request.Headers["X-Forwarded-Proto"] == "https"
&& context.Request.HttpMethod == "GET" && request.Query.Length is > 0 and < 16384;
if(valid)
{
var actual = new UriBuilder(_callback) { Query = request!.Query.TrimStart('?') };
valid = _callbacks.Writer.TryWrite(actual.Uri);
}
context.Response.StatusCode = valid ? 200 : 400;
context.Response.ContentLength64 = 0;
context.Response.Close();
}
}
catch(Exception exception) when(exception is HttpListenerException or ObjectDisposedException)
{
_callbacks.Writer.TryComplete();
}
}
internal ValueTask ReadAsync(CancellationToken token) => _callbacks.Reader.ReadAsync(token);
public void Dispose() => _listener.Close();
}