Engine HttpClient usage fixes.

Properly pool them.
Extend keep-alive timeout for hub advertisements.
Proper user-agents
This commit is contained in:
Pieter-Jan Briers
2022-11-12 00:28:37 +01:00
parent 708b3b2acf
commit d1b16d9a52
6 changed files with 41 additions and 20 deletions

View File

@@ -44,7 +44,9 @@ Template for new versions:
### Other
*None yet*
* Properly re-use `HttpClient` in `NetManager` meaning we properly pool connections to the auth server, improving performance.
* Hub advertisements have extended keep-alive pool timeout, so the connection can be kept active between advertisements.
* All HTTP requests from the engine now have appropriate `User-Agent` header.
### Internal

View File

@@ -1,6 +1,5 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Robust.Shared;
@@ -27,16 +26,7 @@ internal sealed class HubManager
private bool _active;
private bool _firstAdvertisement = true;
private readonly HttpClient _httpClient;
public HubManager()
{
_httpClient = new HttpClient();
var assembly = typeof(HubManager).Assembly.GetName();
if (assembly is { Name: { } name, Version: { } version })
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(name, version.ToString()));
}
private HttpClient? _httpClient;
public async void Start()
{
@@ -46,7 +36,7 @@ internal sealed class HubManager
if (!activate)
return;
_cfg.OnValueChanged(CVars.HubAdvertiseInterval, i => _interval = TimeSpan.FromSeconds(i), true);
_cfg.OnValueChanged(CVars.HubAdvertiseInterval, UpdateInterval, true);
_cfg.OnValueChanged(CVars.HubMasterUrl, s => _masterUrl = s, true);
var url = _cfg.GetCVar(CVars.HubServerUrl);
@@ -70,6 +60,21 @@ internal sealed class HubManager
_advertiseUrl = url;
}
private void UpdateInterval(int interval)
{
_interval = TimeSpan.FromSeconds(interval);
_httpClient?.Dispose();
_httpClient = new HttpClient(new SocketsHttpHandler
{
// Keep-alive connections stay open for longer than the advertise interval.
// This way the same HTTPS connection can be re-used.
PooledConnectionIdleTimeout = _interval + TimeSpan.FromSeconds(10),
});
HttpClientUserAgent.AddUserAgent(_httpClient);
}
public void Heartbeat()
{
if (!_active || _advertiseUrl == null)
@@ -86,12 +91,13 @@ internal sealed class HubManager
private async void SendPing()
{
DebugTools.AssertNotNull(_advertiseUrl);
DebugTools.AssertNotNull(_httpClient);
var apiUrl = $"{_masterUrl}api/servers/advertise";
try
{
using var response = await _httpClient.PostAsJsonAsync(apiUrl, new AdvertiseRequest(_advertiseUrl!));
using var response = await _httpClient!.PostAsJsonAsync(apiUrl, new AdvertiseRequest(_advertiseUrl!));
if (!response.IsSuccessStatusCode)
{
@@ -118,9 +124,11 @@ internal sealed class HubManager
private async Task<string?> GuessAddress()
{
DebugTools.AssertNotNull(_httpClient);
var ipifyUrl = _cfg.GetCVar(CVars.HubIpifyUrl);
var req = await _httpClient.GetFromJsonAsync<IpResponse>(ipifyUrl);
var req = await _httpClient!.GetFromJsonAsync<IpResponse>(ipifyUrl);
return $"ss14://{req!.Ip}:{_cfg.GetCVar(CVars.NetPort)}/";
}

View File

@@ -12,6 +12,7 @@ using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
#nullable enable
@@ -35,6 +36,11 @@ namespace Robust.Server.ServerStatus
private Uri? _baseUri;
private ISawmill _sawmill = default!;
public WatchdogApi()
{
HttpClientUserAgent.AddUserAgent(_httpClient);
}
public void PostInject()
{
_sawmill = Logger.GetSawmill("watchdogApi");

View File

@@ -192,9 +192,10 @@ namespace Robust.Shared.Network
var authHash = Convert.ToBase64String(authHashBytes);
var joinReq = new JoinRequest(authHash);
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SS14Auth", authToken);
var joinResp = await httpClient.PostAsJsonAsync(authServer + "api/session/join", joinReq, cancel);
var request = new HttpRequestMessage(HttpMethod.Post, authServer + "api/session/join");
request.Content = JsonContent.Create(joinReq);
request.Headers.Authorization = new AuthenticationHeaderValue("SS14Auth", authToken);
var joinResp = await _httpClient.SendAsync(request, cancel);
joinResp.EnsureSuccessStatusCode();

View File

@@ -115,9 +115,8 @@ namespace Robust.Shared.Network
var authHashBytes = MakeAuthHash(sharedSecret, CryptoPublicKey!);
var authHash = Base64Helpers.ConvertToBase64Url(authHashBytes);
var client = new HttpClient();
var url = $"{authServer}api/session/hasJoined?hash={authHash}&userId={msgEncResponse.UserId}";
var joinedRespJson = await client.GetFromJsonAsync<HasJoinedResponse>(url);
var joinedRespJson = await _httpClient.GetFromJsonAsync<HasJoinedResponse>(url);
if (joinedRespJson is not {IsValid: true})
{

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Threading;
@@ -133,6 +134,8 @@ namespace Robust.Shared.Network
private readonly HashSet<NetUserId> _awaitingDisconnectToConnect = new HashSet<NetUserId>();
private readonly HttpClient _httpClient = new();
/// <inheritdoc />
public int Port => _config.GetCVar(CVars.NetPort);
@@ -239,6 +242,8 @@ namespace Robust.Shared.Network
throw new InvalidOperationException("NetManager has already been initialized.");
}
HttpClientUserAgent.AddUserAgent(_httpClient);
SynchronizeNetTime();
IsServer = isServer;