55 lines
1.7 KiB
C#
55 lines
1.7 KiB
C#
using PrivaPub.Infrastructure.Geo;
|
|||
|
|
|
||
|
|
using System.Collections.Concurrent;
|
||
|
|
|
||
|
|
namespace PrivaPub.Infrastructure.Http
|
||
|
|
{
|
||
|
|
public interface IEdgeHints
|
||
|
|
{
|
||
|
|
void Remember(string host, CdnProvider cdn);
|
||
|
|
CdnProvider Of(string host);
|
||
|
|
}
|
||
|
|
|
||
|
|
// The CDN each remote host's responses came through, as their headers tell it (CdnCatalog fingerprints), for the
|
||
|
|
// weekly description of the server. Like ConnectedAddresses, memory only: what a host answers is never stored per
|
||
|
|
// request.
|
||
|
|
public class EdgeHints : IEdgeHints
|
||
|
|
{
|
||
|
|
const int MaxHosts = 50_000;
|
||
|
|
|
||
|
|
readonly ConcurrentDictionary<string, CdnProvider> _hints = new(StringComparer.OrdinalIgnoreCase);
|
||
|
|
|
||
|
|
public void Remember(string host, CdnProvider cdn)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(host))
|
||
|
|
return;
|
||
|
|
if (cdn == default)
|
||
|
|
{
|
||
|
|
_hints.TryRemove(host, out _);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (_hints.Count >= MaxHosts)
|
||
|
|
_hints.Clear();
|
||
|
|
_hints[host] = cdn;
|
||
|
|
}
|
||
|
|
|
||
|
|
public CdnProvider Of(string host) => host != default && _hints.TryGetValue(host, out var cdn) ? cdn : default;
|
||
|
|
}
|
||
|
|
|
||
|
|
// On the federation client: reads each response's CDN fingerprint for its host. A response without one forgets the
|
||
|
|
// host's hint, so a server that leaves its CDN is seen as itself again.
|
||
|
|
public class EdgeHintsHandler : DelegatingHandler
|
||
|
|
{
|
||
|
|
readonly IEdgeHints _hints;
|
||
|
|
|
||
|
|
public EdgeHintsHandler(IEdgeHints hints) => _hints = hints;
|
||
|
|
|
||
|
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||
|
|
{
|
||
|
|
var response = await base.SendAsync(request, cancellationToken);
|
||
|
|
if (request.RequestUri is { } uri && (int)response.StatusCode is >= 200 and < 500)
|
||
|
|
_hints.Remember(uri.Host, CdnCatalog.FromResponse(response));
|
||
|
|
return response;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|