Skip to content

Commit ba2e470

Browse files
committed
Changed: Update Sewer56.Update with More Efficient File Size Check & User-Agent fix.
The launcher now consumes the updated Sewer56.Update library (4.1.0) which replaces GET-for-size probes with HEAD requests and sets a User-Agent on all HTTP traffic. Launcher-side wiring: - SharedHttpClient: every static HttpClient now sends the library's ApplicationUserAgent header. - WebDownloadablePackage: GetNameAndSize uses HEAD instead of GET (no body abandoned). DownloadAsync HttpClient also gets a User-Agent. - Startup.cs (pack download): HttpClient now carries a User-Agent. - App.xaml.cs: sets HttpEx.ApplicationUserAgent = "Reloaded-II/<version>" at the very start of OnStartup, before any HTTP request can be issued. Package bumps: Sewer56.Update 4.0.2 -> 4.1.0 Sewer56.Update.Resolvers.GitHub 1.5.2 -> 1.6.0 Sewer56.Update.Resolvers.NuGet 1.4.1 -> 1.5.0 Sewer56.Update.Resolvers.GameBanana 1.4.2 -> 1.5.0
1 parent 1c74f6c commit ba2e470

9 files changed

Lines changed: 98 additions & 12 deletions

File tree

changelog-template.hbs

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
[Read and Discuss in a Browser](https://github.com/Reloaded-Project/Reloaded-II/discussions/473).
22
[Previous Changelog](https://github.com/Reloaded-Project/Reloaded-II/releases/tag/1.30.2).
33

4-
Just a tiny maintenance update. My health hasn't been the best lately- because
5-
I haven't been taking good care of myself. So this is all I can give for now in
6-
some spare time.
4+
Just a tiny maintenance update that took around ~12h of work over the weekend.
5+
My health hasn't been the best lately- because I haven't been taking good care of myself.
6+
So this is all I can give for now in some spare time.
77

8-
# 1.30.3: Startup Freeze Fix & Steam DRM Docs
8+
# 1.30.3: Startup Freeze Fix, Network Hammering Fix & Steam DRM Docs
99

1010
## Fix Launcher Freezing on Startup by @drewmcelhany
1111

@@ -31,8 +31,79 @@ Also hardened the surrounding code while at it:
3131
Fixes [#910](https://github.com/Reloaded-Project/Reloaded-II/issues/910).
3232

3333
(Note: The actual cause is my NuGet server being slow as of late; while gobbling
34-
up gigabytes of RAM. I'm currently investigating why. Regardless, the launcher
35-
should never freeze over a slow server; so the fix applies universally.)
34+
up gigabytes of RAM. I've been investigating why.)
35+
36+
## Fix Server Slowdown / Self-Inflicted DDoS by @Sewer56
37+
38+
Found the cause of the slow server mentioned above.
39+
40+
It was me; to be more exact; a multitude of different issues all piling up:
41+
42+
- Launcher started full file downloads just to get their size
43+
- Launcher didn't send a `User-Agent` header
44+
- Server wrote to the database on every download
45+
- Server re-ran search queries that rarely change
46+
- Server let clients request unbounded result sets
47+
48+
### Launcher Downloading Files to Get Their Size
49+
50+
When checking for mod updates; the launcher needs the file size of each
51+
available update.
52+
53+
To get it, the launcher sent a full `GET` request; which started downloading the file,
54+
and then immediately threw it away. Every user, on every launch, for every
55+
available update.
56+
57+
Multiply that by enough users at once; and we've basically DDoS'd ourselves.
58+
Hence the slowdown, and the RAM gobbling.
59+
60+
Things got worse when I added HTTPS support via a Caddy reverse proxy late last
61+
year; since abandoned downloads now kept a TLS connection open longer per
62+
request.
63+
64+
The size check now issues a `HEAD` request; which gets the file size from headers
65+
alone- no body download.
66+
67+
### Launcher Not Sending a `User-Agent`
68+
69+
The launcher wasn't sending a `User-Agent` header on any of its HTTP requests.
70+
71+
It now does; so I can distinguish scrapers more easily.
72+
73+
The rest of the issues were server-side. The [server itself](https://github.com/Sewer56/BaGet-ReloadedII)
74+
was also not built for the kind of traffic Reloaded gets; so I fixed that too.
75+
Original BaGet was mostly for smaller deployments.
76+
77+
### Batch Download Counts
78+
79+
Every package download ran a database write before returning the file.
80+
81+
These writes fought over the same database lock; queuing everything up.
82+
83+
Download counts (which BaGet doesn't even properly track in the first place) are
84+
now buffered in memory and flushed every 5 seconds.
85+
86+
In local testing this pushed throughput from ~1,100 to ~4,700 req/s; and cut
87+
worst-case latency from 640ms down to 37ms.
88+
89+
### Cache Search and Autocomplete
90+
91+
Search and autocomplete hit the database fresh on every request.
92+
These are now cached in memory.
93+
94+
In local testing this pushed throughput from ~1,470 to ~4,640 req/s; and cut
95+
worst-case latency from 51ms down to 19ms. Results may be stale for up to 2
96+
minutes; but package listings don't change often enough to notice.
97+
98+
### Cap Search Page Size & Fix Total Hit Count
99+
100+
The search endpoint accepted any amount of user requested results; so a request
101+
like `take=100000` would pull a massive result set.
102+
103+
The page size is now capped at 1000; well above what any legitimate client uses.
104+
105+
Also fixed; the `totalHits` field was reporting the page size instead of the
106+
actual total number of matching packages.
36107

37108
## Document Steam DRM Debugging Issues by @nenkai & @Sewer56
38109

source/Reloaded.Mod.Launcher.Lib/Startup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ private static void DownloadAndOpenPackAndExit(string downloadUrl)
163163
downloadUrl = downloadUrl.Substring(Constants.ReloadedPackProtocol.Length + 1);
164164

165165
using var httpClient = new HttpClient();
166+
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(HttpEx.ApplicationUserAgent);
166167
var file = new MemoryStream(Task.Run(() => httpClient.GetByteArrayAsync(downloadUrl)).Result);
167168
var config = IoC.Get<LoaderConfig>();
168169
Actions.ShowInstallModPackDialog(new InstallModPackDialogViewModel(new ReloadedPackReader(file), config, new AggregateNugetRepository(config.NuGetFeeds)));

source/Reloaded.Mod.Launcher.Lib/Usings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
global using Reloaded.Mod.Shared;
5555
global using SevenZip;
5656
global using Sewer56.Update;
57+
global using Sewer56.Update.Http;
5758
global using Sewer56.Update.Extractors.SevenZipSharp;
5859
global using Sewer56.Update.Misc;
5960
global using Sewer56.Update.Packaging.Interfaces;

source/Reloaded.Mod.Launcher/App.xaml.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Environment = Reloaded.Mod.Shared.Environment;
33
using Path = System.IO.Path;
44
using Paths = Reloaded.Mod.Loader.IO.Paths;
5+
using Sewer56.Update.Http;
56

67
namespace Reloaded.Mod.Launcher;
78

@@ -17,6 +18,11 @@ public partial class App : Application
1718

1819
private void OnStartup(object sender, StartupEventArgs e)
1920
{
21+
// Identify our HTTP traffic server-side. Set before any HTTP request is made
22+
// (command-line download handlers may issue requests below).
23+
var ver = typeof(App).Assembly.GetName().Version!;
24+
HttpEx.ApplicationUserAgent = $"Reloaded-II/{ver.Major}.{ver.Minor}.{ver.Build}";
25+
2026
// Run update handler.
2127
if (Sewer56.Update.Hooks.Startup.HandleCommandLineArgs(GetCommandLineArgs()))
2228
{

source/Reloaded.Mod.Loader.Update.Packaging/Reloaded.Mod.Loader.Update.Packaging.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626

2727
<ItemGroup>
2828
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.2.39" PrivateAssets="All" />
29-
<PackageReference Include="Sewer56.Update" Version="4.0.2" />
29+
<PackageReference Include="Sewer56.Update" Version="4.1.0" />
3030
<PackageReference Include="Sewer56.Update.Extractors.SevenZipSharp" Version="1.1.4" GeneratePathProperty="true" />
3131
<PackageReference Include="Sewer56.Update.Packaging" Version="3.0.1" />
32-
<PackageReference Include="Sewer56.Update.Resolvers.NuGet" Version="1.4.1" />
33-
<PackageReference Include="Sewer56.Update.Resolvers.GameBanana" Version="1.4.2" />
32+
<PackageReference Include="Sewer56.Update.Resolvers.NuGet" Version="1.5.0" />
33+
<PackageReference Include="Sewer56.Update.Resolvers.GameBanana" Version="1.5.0" />
3434
<PackageReference Include="System.Formats.Asn1" Version="10.0.0" />
3535
</ItemGroup>
3636

source/Reloaded.Mod.Loader.Update/Providers/Web/WebDownloadablePackage.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public async Task<string> DownloadAsync(string packageFolder, IProgress<double>?
111111

112112
// Start the modification download.
113113
using var httpClient = new HttpClient();
114+
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(HttpEx.ApplicationUserAgent);
114115
var downloadProgress = progressSlicer.Slice(0.9);
115116

116117
await retryPolicy.ExecuteAsync(async () =>
@@ -159,10 +160,12 @@ public async static Task<string> CopyPackagesFromExtractFolderToTargetDir(string
159160

160161
private async Task GetNameAndSize(Uri url)
161162
{
162-
// Obtain the name of the file.
163+
// Obtain the name and size of the file via HEAD (headers only, no body download).
163164
try
164165
{
165166
var fileReq = WebRequest.CreateHttp(url);
167+
HttpEx.ApplyUserAgent(fileReq);
168+
fileReq.Method = "HEAD";
166169
using var fileResp = await fileReq.GetResponseAsync();
167170

168171
try

source/Reloaded.Mod.Loader.Update/Reloaded.Mod.Loader.Update.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
</PackageReference>
4242
<PackageReference Include="RedistributableChecker" Version="0.2.3" />
4343
<PackageReference Include="ReverseMarkdown" Version="4.7.1" />
44-
<PackageReference Include="Sewer56.Update" Version="4.0.2" />
44+
<PackageReference Include="Sewer56.Update" Version="4.1.0" />
4545
<PackageReference Include="Sewer56.Update.Misc" Version="1.1.0" />
46-
<PackageReference Include="Sewer56.Update.Resolvers.GitHub" Version="1.5.2" />
46+
<PackageReference Include="Sewer56.Update.Resolvers.GitHub" Version="1.6.0" />
4747
<PackageReference Include="System.Formats.Asn1" Version="10.0.0" />
4848
<PackageReference Include="System.Net.Http" Version="4.3.4" />
4949
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />

source/Reloaded.Mod.Loader.Update/Usings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
global using ReverseMarkdown;
4949
global using Sewer56.DeltaPatchGenerator.Lib.Utility;
5050
global using Sewer56.Update;
51+
global using Sewer56.Update.Http;
5152
global using Sewer56.Update.Extractors.SevenZipSharp;
5253
global using Sewer56.Update.Interfaces.Extensions;
5354
global using Sewer56.Update.Misc;

source/Reloaded.Mod.Loader.Update/Utilities/SharedHttpClient.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public static HttpClient CachedAndCompressed
2323
{
2424
AutomaticDecompression = DecompressionMethods.All
2525
});
26+
_cachedAndCompressed.DefaultRequestHeaders.UserAgent.ParseAdd(HttpEx.ApplicationUserAgent);
2627

2728
return _cachedAndCompressed;
2829
}
@@ -39,6 +40,7 @@ public static HttpClient Cached
3940
return _cached;
4041

4142
_cached = AkavacheWebCacheStore.Instance.CreateClient();
43+
_cached.DefaultRequestHeaders.UserAgent.ParseAdd(HttpEx.ApplicationUserAgent);
4244
return _cached;
4345
}
4446
}
@@ -57,6 +59,7 @@ public static HttpClient UncachedAndCompressed
5759
{
5860
AutomaticDecompression = DecompressionMethods.All
5961
});
62+
_uncachedAndCompressed.DefaultRequestHeaders.UserAgent.ParseAdd(HttpEx.ApplicationUserAgent);
6063

6164
return _uncachedAndCompressed;
6265
}

0 commit comments

Comments
 (0)