Skip to content

Commit c0abb58

Browse files
authored
Support Content-Disposition header for download filenames (#419)
Add parameter to allow downloads to prefer to use the name provided by the server for downloaded files
1 parent dbaf378 commit c0abb58

File tree

4 files changed

+36
-26
lines changed

4 files changed

+36
-26
lines changed

ModAssistant/Classes/External Interfaces/Playlists.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.IO;
33
using System.Linq;
44
using System.Threading.Tasks;
5-
using System.Web;
65
using System.Windows;
76
using static ModAssistant.Http;
87

@@ -34,14 +33,11 @@ public static async Task DownloadAll(Uri uri)
3433

3534
public static async Task<string> Get(Uri url)
3635
{
37-
string filename = HttpUtility.UrlDecode(url.Segments.Last());
38-
string absolutePath = Path.Combine(BeatSaberPath, PlaylistsFolder, filename);
3936
try
4037
{
4138
CreatePlaylistsFolder();
42-
await Utils.DownloadAsset(url.ToString(), PlaylistsFolder, filename);
43-
44-
return absolutePath;
39+
string filename = await Utils.DownloadAsset(url.ToString(), PlaylistsFolder, preferContentDisposition: true);
40+
return Path.Combine(BeatSaberPath, PlaylistsFolder, filename);
4541
}
4642
catch
4743
{

ModAssistant/Classes/External Interfaces/Utils.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,50 +29,49 @@ public static void SetMessage(string message)
2929
}
3030
}
3131

32-
public static async Task DownloadAsset(string link, string folder, bool showNotifcation, string fileName = null)
33-
{
34-
await DownloadAsset(link, folder, fileName, null, showNotifcation);
35-
}
36-
37-
public static async Task DownloadAsset(string link, string folder, string fileName = null, string displayName = null)
38-
{
39-
await DownloadAsset(link, folder, fileName, displayName, true);
40-
}
41-
42-
public static async Task DownloadAsset(string link, string folder, string fileName, string displayName, bool showNotification, bool beatsaver = false)
32+
public static async Task<string> DownloadAsset(string link, string folder, string fileName = null, string displayName = null, bool showNotification = true, bool beatsaver = false, bool preferContentDisposition = false)
4333
{
4434
if (string.IsNullOrEmpty(BeatSaberPath))
4535
{
4636
ModAssistant.Utils.SendNotify((string)Application.Current.FindResource("OneClick:InstallDirNotFound"));
4737
}
4838
try
4939
{
50-
Directory.CreateDirectory(Path.Combine(BeatSaberPath, folder));
40+
var parentDir = Path.Combine(BeatSaberPath, folder);
41+
Directory.CreateDirectory(parentDir);
42+
5143
if (string.IsNullOrEmpty(fileName))
5244
{
53-
fileName = WebUtility.UrlDecode(Path.Combine(BeatSaberPath, folder, new Uri(link).Segments.Last()));
45+
fileName = new Uri(link).Segments.Last();
46+
}
47+
48+
if (beatsaver)
49+
{
50+
fileName = WebUtility.UrlDecode(Path.Combine(parentDir, fileName));
51+
await BeatSaver.Download(link, fileName);
5452
}
5553
else
5654
{
57-
fileName = WebUtility.UrlDecode(Path.Combine(BeatSaberPath, folder, fileName));
55+
fileName = await ModAssistant.Utils.Download(link, parentDir, fileName, preferContentDisposition);
5856
}
57+
5958
if (string.IsNullOrEmpty(displayName))
6059
{
6160
displayName = Path.GetFileNameWithoutExtension(fileName);
6261
}
6362

64-
if (beatsaver) await BeatSaver.Download(link, fileName);
65-
else await ModAssistant.Utils.Download(link, fileName);
66-
6763
if (showNotification)
6864
{
6965
SetMessage(string.Format((string)Application.Current.FindResource("OneClick:InstalledAsset"), displayName));
7066
}
67+
68+
return fileName;
7169
}
7270
catch
7371
{
7472
SetMessage((string)Application.Current.FindResource("OneClick:AssetInstallFailed"));
7573
App.CloseWindowOnFinish = false;
74+
return null;
7675
}
7776
}
7877
}

ModAssistant/Classes/Updater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public static async Task StartUpdate()
7777

7878
File.Move(Utils.ExePath, OldExe);
7979

80-
await Utils.Download(DownloadLink, NewExe);
80+
await Utils.Download(DownloadLink, "", NewExe);
8181
RunNew();
8282
}
8383
}

ModAssistant/Classes/Utils.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.IO;
66
using System.Linq;
77
using System.Management;
8+
using System.Net;
89
using System.Security.Cryptography;
910
using System.Security.Principal;
1011
using System.Text;
@@ -438,14 +439,28 @@ public static void Log(string message, string severity = "LOG")
438439
File.AppendAllText(logFile, $"[{DateTime.UtcNow:yyyy-mm-dd HH:mm:ss.ffffff}][{severity.ToUpper()}] {message}\n");
439440
}
440441

441-
public static async Task Download(string link, string output)
442+
public static async Task<string> Download(string link, string folder, string output, bool preferContentDisposition = false)
442443
{
443444
var resp = await HttpClient.GetAsync(link);
445+
var cdFilename = resp.Content.Headers.ContentDisposition.FileName.Trim('"');
446+
// Prevent path traversal
447+
if (cdFilename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
448+
{
449+
cdFilename = null;
450+
}
451+
452+
var filename = WebUtility.UrlDecode(Path.Combine(
453+
folder,
454+
(preferContentDisposition ? cdFilename : null) ?? output
455+
));
456+
444457
using (var stream = await resp.Content.ReadAsStreamAsync())
445-
using (var fs = new FileStream(output, FileMode.OpenOrCreate, FileAccess.Write))
458+
using (var fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write))
446459
{
447460
await stream.CopyToAsync(fs);
448461
}
462+
463+
return filename;
449464
}
450465

451466
private delegate void ShowMessageBoxDelegate(string Message, string Caption);

0 commit comments

Comments
 (0)