mirror of
https://github.com/alexhopeoconnor/dnsmasq-webui.git
synced 2026-10-03 22:12:00 +10:00
Fix log download race; stream live log file (v0.0.10)
Replace ReadAllTextAsync with FileStream + FileShare.ReadWrite so concurrent dnsmasq writes cannot trigger StringBuilder capacity errors. Release as 0.0.10.
This commit is contained in:
@@ -163,32 +163,39 @@ public class StatusController : ControllerBase
|
|||||||
|
|
||||||
/// <summary>Returns the full log file from the path in effective config (log-facility). Untruncated.</summary>
|
/// <summary>Returns the full log file from the path in effective config (log-facility). Untruncated.</summary>
|
||||||
[HttpGet("logs/download")]
|
[HttpGet("logs/download")]
|
||||||
public async Task<IActionResult> GetLogsDownload(CancellationToken ct)
|
public Task<IActionResult> GetLogsDownload(CancellationToken ct)
|
||||||
{
|
{
|
||||||
var (effectiveConfig, _) = _configSetService.GetEffectiveConfigWithSources();
|
var (effectiveConfig, _) = _configSetService.GetEffectiveConfigWithSources();
|
||||||
var logsPath = EffectiveDnsmasqConfig.GetLogsPath(effectiveConfig);
|
var logsPath = EffectiveDnsmasqConfig.GetLogsPath(effectiveConfig);
|
||||||
if (string.IsNullOrEmpty(logsPath))
|
if (string.IsNullOrEmpty(logsPath))
|
||||||
return NotFound();
|
return Task.FromResult<IActionResult>(NotFound());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
_logger.LogDebug("Get status logs download");
|
_logger.LogDebug("Get status logs download");
|
||||||
var fullPath = Path.IsPathRooted(logsPath) ? Path.GetFullPath(logsPath) : Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), logsPath));
|
var fullPath = Path.IsPathRooted(logsPath) ? Path.GetFullPath(logsPath) : Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), logsPath));
|
||||||
if (!System.IO.File.Exists(fullPath))
|
if (!System.IO.File.Exists(fullPath))
|
||||||
return NotFound();
|
return Task.FromResult<IActionResult>(NotFound());
|
||||||
|
|
||||||
var content = await System.IO.File.ReadAllTextAsync(fullPath, System.Text.Encoding.UTF8, ct);
|
|
||||||
var fileName = Path.GetFileName(fullPath);
|
var fileName = Path.GetFileName(fullPath);
|
||||||
if (string.IsNullOrEmpty(fileName)) fileName = "dnsmasq.log";
|
if (string.IsNullOrEmpty(fileName)) fileName = "dnsmasq.log";
|
||||||
return File(
|
|
||||||
System.Text.Encoding.UTF8.GetBytes(content),
|
// ReadAllTextAsync pre-allocates from Length; concurrent log writes can grow the file mid-read
|
||||||
"text/plain",
|
// and trigger ArgumentOutOfRangeException. Stream with FileShare.ReadWrite and stream the response.
|
||||||
fileName);
|
var stream = new FileStream(
|
||||||
|
fullPath,
|
||||||
|
FileMode.Open,
|
||||||
|
FileAccess.Read,
|
||||||
|
FileShare.ReadWrite | FileShare.Delete,
|
||||||
|
bufferSize: 64 * 1024,
|
||||||
|
FileOptions.Asynchronous | FileOptions.SequentialScan);
|
||||||
|
return Task.FromResult<IActionResult>(File(stream, "text/plain; charset=utf-8", fileName));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Status logs download failed");
|
_logger.LogError(ex, "Status logs download failed");
|
||||||
return StatusCode(500, new { error = ex.Message });
|
return Task.FromResult<IActionResult>(StatusCode(500, new { error = ex.Message }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>0.0.9</Version>
|
<Version>0.0.10</Version>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<!-- Avoid pre-compressed .br/.gz so MapStaticAssets serves uncompressed files (fixes 0-byte/empty response bug). -->
|
<!-- Avoid pre-compressed .br/.gz so MapStaticAssets serves uncompressed files (fixes 0-byte/empty response bug). -->
|
||||||
<DisableBuildCompression>true</DisableBuildCompression>
|
<DisableBuildCompression>true</DisableBuildCompression>
|
||||||
|
|||||||
Reference in New Issue
Block a user