diff --git a/Duplicati/WebserverCore/Middlewares/StaticFilesMiddleware.cs b/Duplicati/WebserverCore/Middlewares/StaticFilesMiddleware.cs
index 7c6119076..c9aa5124e 100644
--- a/Duplicati/WebserverCore/Middlewares/StaticFilesMiddleware.cs
+++ b/Duplicati/WebserverCore/Middlewares/StaticFilesMiddleware.cs
@@ -49,17 +49,17 @@ public static class StaticFilesExtensions
MaxAge = TimeSpan.FromDays(7)
};
- private sealed record SpaConfig(string Prefix, byte[] IndexFile, string BasePath);
+ private const string FORWARDED_PREFIX_HEADER = "X-Forwarded-Prefix";
+ private const string DEFAULT_FORWARDED_PREFIX = "/ngclient";
- private static byte[] ReadAndPatchIndexFile(FileInfo file, string prefix)
+ private sealed record SpaConfig(string Prefix, string FileContent, string BasePath);
+
+ private static string PatchIndexContent(string fileContent, string prefix)
{
if (!prefix.EndsWith("/"))
prefix += "/";
- var index = File.ReadAllBytes(file.FullName);
- var indexStr = Encoding.UTF8.GetString(index);
- indexStr = indexStr.Replace("", $"");
- return Encoding.UTF8.GetBytes(indexStr);
+ return fileContent.Replace("", $"");
}
public static IApplicationBuilder UseDefaultStaticFiles(this WebApplication app, string webroot, IEnumerable spaPaths)
@@ -91,7 +91,7 @@ public static class StaticFilesExtensions
var fi = new FileInfo(file);
if (fi.Exists)
{
- prefixHandlerMap.Add(new SpaConfig(prefix, ReadAndPatchIndexFile(fi, prefix), basepath));
+ prefixHandlerMap.Add(new SpaConfig(prefix, File.ReadAllText(fi.FullName), basepath));
}
#if DEBUG
else
@@ -99,9 +99,9 @@ public static class StaticFilesExtensions
// Install from NPM in debug mode for easier development
var spaConfig = NpmSpaHelper.ProbeForNpmSpa(basepath);
if (spaConfig != null)
- prefixHandlerMap.Add(new SpaConfig(prefix, ReadAndPatchIndexFile(spaConfig.IndexFile, prefix), spaConfig.BasePath));
+ prefixHandlerMap.Add(new SpaConfig(prefix, File.ReadAllText(spaConfig.IndexFile.FullName), spaConfig.BasePath));
else if (spaConfig == null && missingFile.Exists)
- prefixHandlerMap.Add(new SpaConfig(prefix, File.ReadAllBytes(missingFile.FullName), basepath));
+ prefixHandlerMap.Add(new SpaConfig(prefix, File.ReadAllText(missingFile.FullName), basepath));
}
#endif
}
@@ -132,11 +132,16 @@ public static class StaticFilesExtensions
// Serve the index file
context.Response.ContentType = "text/html";
context.Response.StatusCode = 200;
+ var indexContent = spaConfig.FileContent;
#if DEBUG
- await context.Response.Body.WriteAsync(ReadAndPatchIndexFile(new FileInfo(Path.Combine(spaConfig.BasePath, "index.html")), spaConfig.Prefix));
-#else
- await context.Response.Body.WriteAsync(spaConfig.IndexFile);
-#endif
+ // In debug mode, we re-read the index file to ensure we have the latest content for debugging
+ indexContent = File.ReadAllText(Path.Combine(spaConfig.BasePath, "index.html"));
+#endif
+ var forwardedPrefix = context.Request.Headers[FORWARDED_PREFIX_HEADER].FirstOrDefault();
+ if (string.IsNullOrEmpty(forwardedPrefix))
+ forwardedPrefix = DEFAULT_FORWARDED_PREFIX;
+
+ await context.Response.WriteAsync(PatchIndexContent(indexContent, forwardedPrefix), context.RequestAborted);
await context.Response.CompleteAsync();
}
else