Skip to content

Commit 81bcbfc

Browse files
author
Meyn
committed
Update SiteRequest
1 parent 39fdf2f commit 81bcbfc

File tree

13 files changed

+2396
-996
lines changed

13 files changed

+2396
-996
lines changed

DownloadAssistant/Base/HttpClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static HttpClient HttpClient
2121
lock (_lockObject) _httpClient ??= CreateHttpClient();
2222
return _httpClient;
2323
}
24+
set => _httpClient = value;
2425
}
2526

2627
private static HttpClient CreateHttpClient()

DownloadAssistant/Base/HttpGet.cs

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ public LoadRange Range
3939
/// </summary>
4040
public CancellationToken Token { get; init; }
4141

42-
4342
/// <summary>
4443
/// Gets the exception if the HEAD request failed.
4544
/// </summary>
@@ -103,25 +102,55 @@ private long LoadContentLength()
103102
catch (Exception ex)
104103
{
105104
HeadRequestException = new NotSupportedException("The length of the content could not be loaded, because the requested server does not support this function.", ex);
106-
Debug.Assert(false, ex.Message);
105+
Debug.Fail(ex.Message);
107106
}
108107
if (!Range.IsEmpty && length > 0)
109108
SetRange(length);
110109
return length;
111110
}
112111

113112
/// <summary>
114-
/// Retrieves the content length from the server.
113+
/// Retrieves content length with HEAD request fallback to partial GET
115114
/// </summary>
116115
/// <returns>The content length.</returns>
117-
private long GetContentLength()
116+
private long GetContentLength() => GetContentLengthViaHead() ?? GetContentLengthViaPartialGet() ?? 0;
117+
118+
/// <summary>
119+
/// Gets content length using HEAD request
120+
/// </summary>
121+
private long? GetContentLengthViaHead()
118122
{
119-
HttpRequestMessage msg = CloneRequestMessage(_originalMessage);
120-
msg.Method = HttpMethod.Head;
121-
HttpResponseMessage res = HttpClient.Send(msg, TimedTokenOrDefault());
122-
if (res.IsSuccessStatusCode)
123-
return res.Content.Headers.ContentLength ?? 0;
124-
return 0;
123+
try
124+
{
125+
using HttpRequestMessage msg = CloneRequestMessage(_originalMessage);
126+
msg.Method = HttpMethod.Head;
127+
using HttpResponseMessage response = HttpClient.Send(msg, TimedTokenOrDefault());
128+
response.EnsureSuccessStatusCode();
129+
return response.Content.Headers.ContentLength ?? response.Content.Headers.ContentRange?.Length;
130+
}
131+
catch { return null; }
132+
}
133+
134+
/// <summary>
135+
/// Gets content length using range request fallback
136+
/// </summary>
137+
138+
private long? GetContentLengthViaPartialGet()
139+
{
140+
LoadRange originalRange = _range;
141+
try
142+
{
143+
_range = new LoadRange(0, 0);
144+
using HttpRequestMessage msg = CloneRequestMessage(_originalMessage);
145+
msg.Headers.Range = new RangeHeaderValue(0, 0);
146+
147+
using HttpResponseMessage response = HttpClient.Send(msg, TimedTokenOrDefault());
148+
response.EnsureSuccessStatusCode();
149+
150+
return response.Content.Headers.ContentRange?.Length ?? response.Content.Headers.ContentLength;
151+
}
152+
catch { return null; }
153+
finally { _range = originalRange; }
125154
}
126155

127156
/// <summary>
@@ -130,6 +159,8 @@ private long GetContentLength()
130159
/// <returns>The response message.</returns>
131160
public async Task<HttpResponseMessage> LoadResponseAsync()
132161
{
162+
if (_disposed)
163+
throw new ObjectDisposedException(GetType().FullName);
133164
if (!IsLengthSet(out HttpResponseMessage res))
134165
return res;
135166

DownloadAssistant/Base/UserAgentBuilder.cs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ public static string Generate()
2525
/// <param name="architecture">System architecture information</param>
2626
/// <param name="deviceModel">Device model information (optional)</param>
2727
/// <returns>Complete User-Agent string with all placeholders replaced</returns>
28-
private static string ComposeUserAgent(
29-
PlatformTemplate template,
30-
string architecture,
31-
string deviceModel = "")
28+
private static string ComposeUserAgent(PlatformTemplate template, string architecture, string deviceModel = "")
3229
{
3330
const string chromeVersion = "124.0.6367.79";
3431
const string webKitToken = "AppleWebKit/537.36 (KHTML, like Gecko)";
@@ -55,14 +52,11 @@ private static string ComposeUserAgent(
5552
/// <param name="format">String containing placeholders</param>
5653
/// <param name="values">Dictionary of placeholder-value pairs</param>
5754
/// <returns>Formatted string with replaced values</returns>
58-
private static string ReplaceNamedPlaceholders(
59-
string format,
60-
IReadOnlyDictionary<string, object> values)
55+
private static string ReplaceNamedPlaceholders(string format, IReadOnlyDictionary<string, object> values)
6156
{
6257
foreach (KeyValuePair<string, object> kvp in values)
63-
{
6458
format = format.Replace(kvp.Key, kvp.Value.ToString() ?? string.Empty);
65-
}
59+
6660
return format;
6761
}
6862

@@ -79,9 +73,7 @@ private record PlatformTemplate(string FormatString, Version OsVersion);
7973
/// <param name="osPlatform">Target operating system platform</param>
8074
/// <param name="osVersion">Operating system version</param>
8175
/// <returns>Platform-specific User-Agent template</returns>
82-
private static PlatformTemplate GetPlatformTemplate(
83-
OSPlatform osPlatform,
84-
Version osVersion)
76+
private static PlatformTemplate GetPlatformTemplate(OSPlatform osPlatform, Version osVersion)
8577
{
8678
Dictionary<OSPlatform, Func<Version, PlatformTemplate>> templates = new()
8779
{
@@ -174,17 +166,13 @@ private static (OSPlatform Platform, Version Version) GetOSInfo()
174166
/// Determines if the current OS is Android
175167
/// </summary>
176168
/// <returns>True if running on Android, false otherwise</returns>
177-
private static bool IsAndroid() =>
178-
RuntimeInformation.OSDescription.Contains("Android", StringComparison.OrdinalIgnoreCase) ||
179-
Environment.OSVersion.VersionString.Contains("Android");
169+
private static bool IsAndroid() => RuntimeInformation.OSDescription.Contains("Android", StringComparison.OrdinalIgnoreCase) || Environment.OSVersion.VersionString.Contains("Android");
180170

181171
/// <summary>
182172
/// Determines if the current OS is Tizen
183173
/// </summary>
184174
/// <returns>True if running on Tizen, false otherwise</returns>
185-
private static bool IsTizen() =>
186-
RuntimeInformation.OSDescription.Contains("Tizen", StringComparison.OrdinalIgnoreCase) ||
187-
Environment.OSVersion.VersionString.Contains("Tizen");
175+
private static bool IsTizen() => RuntimeInformation.OSDescription.Contains("Tizen", StringComparison.OrdinalIgnoreCase) || Environment.OSVersion.VersionString.Contains("Tizen");
188176

189177
/// <summary>
190178
/// Attempts to retrieve the Android device model

DownloadAssistant/DownloadAssistant.csproj

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<PackageProjectUrl></PackageProjectUrl>
1111
<PackageIcon>logo.png</PackageIcon>
1212
<PackageReadmeFile>README.md</PackageReadmeFile>
13-
<Version>1.0.9</Version>
13+
<Version>1.1.0</Version>
1414
<GenerateDocumentationFile>True</GenerateDocumentationFile>
1515
<Description>A free to use library as a download manager.
1616
Includes retry, priority, cancel, etc.. function.
@@ -26,7 +26,10 @@ Features:
2626
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
2727
<Company>Shard</Company>
2828
<Authors>Meyn</Authors>
29-
<PackageReleaseNotes>Improved handling and falback for retrieving Downloads folder path on Windows</PackageReleaseNotes>
29+
<PackageReleaseNotes>Easier access to individual progress and speed reporter
30+
Update HttpClient and User Agent Generation
31+
Enhance StatusRequest to Parse Additional Data
32+
Update SiteRequest</PackageReleaseNotes>
3033
<RepositoryUrl>https://github.com/TypNull/DownloadAssistant</RepositoryUrl>
3134
</PropertyGroup>
3235

@@ -49,6 +52,21 @@ Features:
4952
<PackageReference Include="Shard.Requests" Version="2.2.1" />
5053
</ItemGroup>
5154

55+
<ItemGroup>
56+
<Compile Update="Media\MimeTypes.Designer.cs">
57+
<DesignTime>True</DesignTime>
58+
<AutoGen>True</AutoGen>
59+
<DependentUpon>MimeTypes.resx</DependentUpon>
60+
</Compile>
61+
</ItemGroup>
62+
63+
<ItemGroup>
64+
<EmbeddedResource Update="Media\MimeTypes.resx">
65+
<Generator>ResXFileCodeGenerator</Generator>
66+
<LastGenOutput>MimeTypes.Designer.cs</LastGenOutput>
67+
</EmbeddedResource>
68+
</ItemGroup>
69+
5270
<ItemGroup>
5371
<None Update="logo.png">
5472
<Pack>True</Pack>

DownloadAssistant/Media/FileMetadata.cs renamed to DownloadAssistant/Media/FileNameExtractor.cs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,26 @@
66
namespace DownloadAssistant.Media
77
{
88
/// <summary>
9-
/// Provides file metadata extraction and sanitization capabilities for downloaded content.
9+
/// Provides file name extraction and sanitization capabilities for downloaded content.
1010
/// </summary>
11-
public class FileMetadata
11+
public class FileNameExtractor
12+
1213
{
1314
private readonly HttpContentHeaders _headers;
1415
private readonly Uri _uri;
1516

1617
private static readonly string[] DispositionHeaders = { /* IETF Standard */ "Content-Disposition", "X-Content-Disposition" };
1718

18-
private static readonly string[] FilenameHeaders ={
19+
private static readonly string[] FilenameHeaders =
20+
{
1921
/* Cloud Provider Headers */ "X-Amz-Meta-Filename", "x-ms-meta-Filename", "X-Google-Filename",
2022
/* Framework Headers */ "X-Django-FileName", "X-File-Key",
2123
/* CDN/Proxy Headers */ "X-Original-Filename", "X-Source-Filename",
2224
/* Common Industry Headers */ "X-Filename","X-File-Name", "X-Object-Name"
2325
};
2426

25-
private static readonly string[] RedirectHeaders = {
27+
private static readonly string[] RedirectHeaders =
28+
{
2629
/* RFC 7231 Standard */ "Location",
2730
/* Nginx */ "X-Accel-Redirect",
2831
/* Apache */ "X-Sendfile"
@@ -57,7 +60,7 @@ public class FileMetadata
5760
/// </summary>
5861
/// <param name="headers">HTTP content headers from the response.</param>
5962
/// <param name="uri">Source URI of the downloaded content.</param>
60-
public FileMetadata(HttpContentHeaders headers, Uri uri)
63+
public FileNameExtractor(HttpContentHeaders headers, Uri uri)
6164
{
6265
_headers = headers;
6366
_uri = uri;
@@ -68,12 +71,8 @@ public FileMetadata(HttpContentHeaders headers, Uri uri)
6871
/// <summary>
6972
/// Determines the file extension from Content-Type header or URI path.
7073
/// </summary>
71-
private void SetExtension()
72-
{
73-
Extension = _headers.ContentType?.MediaType != null
74-
? MimeTypeMap.GetDefaultExtension(_headers.ContentType.MediaType)
75-
: Path.GetExtension(_uri.AbsoluteUri);
76-
}
74+
private void SetExtension() => Extension = _headers.ContentType?.MediaType != null ? MimeTypeMap.GetDefaultExtension(_headers.ContentType.MediaType) : Path.GetExtension(_uri.AbsoluteUri);
75+
7776

7877
/// <summary>
7978
/// Main filename determination workflow with fallback strategies.
@@ -155,14 +154,12 @@ private void SetFilename()
155154
/// Coordinates multiple alternate filename discovery strategies.
156155
/// </summary>
157156
/// <returns>Valid filename or null if not found.</returns>
158-
private string? GetFilenameFromAlternateSources()
159-
{
160-
return ExtractFromQueryParameters()
157+
private string? GetFilenameFromAlternateSources() => ExtractFromQueryParameters()
161158
?? ExtractFromContentHeaders()
162159
?? ExtractFromRedirectHeaders()
163160
?? ExtractFromCustomHeaders()
164161
?? ExtractFromContentType();
165-
}
162+
166163

167164
/// <summary>
168165
/// Extracts filename from content-related headers (Content-Location, etc.).
@@ -243,7 +240,7 @@ private void SetFilename()
243240
return Path.GetFileName(decoded).Trim();
244241
}
245242
}
246-
catch { /* Log error if needed */ }
243+
catch { }
247244
return null;
248245
}
249246

@@ -301,9 +298,7 @@ private string SanitizeFilename(string fileName)
301298
string baseName = Path.GetFileNameWithoutExtension(cleanName);
302299

303300
int allowedBaseLength = maxLength - extension.Length;
304-
return allowedBaseLength <= 0
305-
? cleanName[..maxLength]
306-
: $"{baseName[..allowedBaseLength]}{extension}";
301+
return allowedBaseLength <= 0 ? cleanName[..maxLength] : $"{baseName[..allowedBaseLength]}{extension}";
307302
}
308303

309304
/// <summary>

0 commit comments

Comments
 (0)