diff --git a/.nuget/nuget.exe b/.nuget/nuget.exe new file mode 100644 index 0000000..94aada9 Binary files /dev/null and b/.nuget/nuget.exe differ diff --git a/src/HttpFileServer/Handlers/HttpGetHandler.cs b/src/HttpFileServer/Handlers/HttpGetHandler.cs index 77fa6be..f5b88a9 100644 --- a/src/HttpFileServer/Handlers/HttpGetHandler.cs +++ b/src/HttpFileServer/Handlers/HttpGetHandler.cs @@ -262,28 +262,47 @@ protected async Task> GetResponseContentTypeAndStrea Stream stream = null; var fileExist = false; + // Guard against path traversal: ensure resolved path stays within SourceDir + string safeRoot, safePath; + try + { + safeRoot = Path.GetFullPath(SourceDir); + safePath = Path.GetFullPath(path); + } + catch (Exception) + { + // Invalid path characters or other path resolution errors + return new Tuple(contentType, null, false); + } + if (!safePath.StartsWith(safeRoot + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) && + !safePath.Equals(safeRoot, StringComparison.OrdinalIgnoreCase)) + { + System.Diagnostics.Trace.TraceWarning($"Path traversal attempt blocked: resolved path outside SourceDir"); + return new Tuple(contentType, null, false); + } + var data = _cacheSrv?.GetCache(path); if (data is null) { - if (File.Exists(path)) + if (File.Exists(safePath)) { - await FileAccessHelper.AddAccessCount(path); + await FileAccessHelper.AddAccessCount(safePath); fileExist = true; - stream = new FileStream(path, FileMode.Open, FileAccess.Read); + stream = new FileStream(safePath, FileMode.Open, FileAccess.Read, FileShare.Read); contentType = "application/octet-stream"; } - else if (Directory.Exists(path)) + else if (Directory.Exists(safePath)) { - var location = Path.GetFileName(path); + var location = Path.GetFileName(safePath); var title = "HttpFileServer"; - if (path != SourceDir) + if (safePath != SourceDir) { - location = Path.GetFileName(SourceDir) + "\\" + path.Replace(SourceDir, "").Trim('\\'); - title = Path.GetFileName(path.TrimEnd('\\')) + " -- HttpFileServer"; + location = Path.GetFileName(SourceDir) + "\\" + safePath.Replace(SourceDir, "").Trim('\\'); + title = Path.GetFileName(safePath.TrimEnd('\\')) + " -- HttpFileServer"; } - var content = HtmlExtension.GenerateHtmlContentForDir(SourceDir, path, path != SourceDir, EnableUpload, location, title, _debugResourceDir); + var content = HtmlExtension.GenerateHtmlContentForDir(SourceDir, safePath, safePath != SourceDir, EnableUpload, location, title, _debugResourceDir); data = Encoding.UTF8.GetBytes(content); - _cacheSrv?.SaveCache(path, data); + _cacheSrv?.SaveCache(safePath, data); stream = new MemoryStream(data); } } @@ -489,6 +508,7 @@ protected async Task ResponseContentFull(string path, HttpListenerRequest reques response.StatusCode = (int)HttpStatusCode.NotFound; return; } + response.AddHeader("Accept-Ranges", "bytes"); response.ContentLength64 = stream.Length; try { @@ -504,7 +524,7 @@ protected async Task ResponseContentFull(string path, HttpListenerRequest reques { if (tp.Item3) { - FileAccessHelper.SubAccessCount(path); + FileAccessHelper.SubAccessCount(Path.GetFullPath(path)); } stream.Close(); } @@ -556,9 +576,11 @@ protected async Task ResponseContentPartial(string path, HttpListenerRequest req return; } response.AddHeader("Content-Range", $"bytes {range.Item1}-{range.Item2}/{stream.Length}"); + response.AddHeader("Accept-Ranges", "bytes"); var buff = new byte[81920]; var rangeEnd = range.Item2 > range.Item1 ? range.Item2 : stream.Length - 1; var bytesNeeds = rangeEnd - range.Item1 + 1; + response.ContentLength64 = bytesNeeds; response.StatusCode = (int)HttpStatusCode.PartialContent; try { @@ -586,7 +608,7 @@ protected async Task ResponseContentPartial(string path, HttpListenerRequest req { if (tp.Item3) { - FileAccessHelper.SubAccessCount(path); + FileAccessHelper.SubAccessCount(Path.GetFullPath(path)); } stream.Close(); } diff --git a/src/HttpFileServer/Services/FileAccessHelper.cs b/src/HttpFileServer/Services/FileAccessHelper.cs index b7b1bb5..1f19396 100644 --- a/src/HttpFileServer/Services/FileAccessHelper.cs +++ b/src/HttpFileServer/Services/FileAccessHelper.cs @@ -26,7 +26,7 @@ static FileAccessHelper() #region Properties - public static int LimitCount { get; set; } = 2; + public static int LimitCount { get; set; } = 32; #endregion Properties