void.cat/VoidCat/Controllers/DownloadController.cs

109 lines
3.1 KiB
C#
Raw Normal View History

2022-02-08 23:52:01 +00:00
using System.Net;
2022-01-25 23:39:51 +00:00
using Microsoft.AspNetCore.Mvc;
using VoidCat.Model;
using VoidCat.Services;
namespace VoidCat.Controllers;
[Route("d")]
public class DownloadController : Controller
{
2022-02-08 18:20:59 +00:00
private readonly IFileStore _storage;
2022-02-08 23:52:01 +00:00
private readonly ILogger<DownloadController> _logger;
2022-01-25 23:39:51 +00:00
2022-02-08 23:52:01 +00:00
public DownloadController(IFileStore storage, ILogger<DownloadController> logger)
2022-01-25 23:39:51 +00:00
{
_storage = storage;
2022-02-08 23:52:01 +00:00
_logger = logger;
2022-01-25 23:39:51 +00:00
}
2022-02-08 23:52:01 +00:00
[HttpOptions]
[Route("{id}")]
public Task DownloadFileOptions([FromRoute] string id)
{
var gid = id.FromBase58Guid();
return SetupDownload(gid);
}
2022-02-08 23:56:35 +00:00
2022-01-28 00:18:27 +00:00
[ResponseCache(Location = ResponseCacheLocation.Any, Duration = 86400)]
2022-01-25 23:39:51 +00:00
[HttpGet]
[Route("{id}")]
public async Task DownloadFile([FromRoute] string id)
{
var gid = id.FromBase58Guid();
2022-02-08 23:52:01 +00:00
var meta = await SetupDownload(gid);
var egressReq = new EgressRequest(gid, GetRanges(Request, (long)meta!.Size));
if (egressReq.Ranges.Count() > 1)
{
_logger.LogWarning("Multi-range request not supported!");
// downgrade to full send
egressReq = egressReq with
{
Ranges = Enumerable.Empty<RangeRequest>()
};
}
2022-02-08 23:56:35 +00:00
else if (egressReq.Ranges.Count() == 1)
2022-02-08 23:52:01 +00:00
{
Response.StatusCode = (int)HttpStatusCode.PartialContent;
}
else
{
Response.Headers.AcceptRanges = "bytes";
}
2022-02-08 23:56:35 +00:00
2022-02-08 23:52:01 +00:00
foreach (var range in egressReq.Ranges)
{
Response.Headers.Add("content-range", range.ToContentRange());
Response.ContentLength = range.Size;
}
var cts = HttpContext.RequestAborted;
await Response.StartAsync(cts);
await _storage.Egress(egressReq, Response.Body, cts);
await Response.CompleteAsync();
}
private async Task<VoidFile?> SetupDownload(Guid id)
{
var meta = await _storage.Get(id);
2022-01-25 23:39:51 +00:00
if (meta == null)
{
Response.StatusCode = 404;
2022-02-08 23:52:01 +00:00
return null;
2022-01-25 23:39:51 +00:00
}
2022-02-08 23:56:35 +00:00
2022-02-03 23:06:39 +00:00
Response.Headers.XFrameOptions = "SAMEORIGIN";
Response.Headers.ContentDisposition = $"inline; filename=\"{meta?.Metadata?.Name}\"";
2022-01-25 23:39:51 +00:00
Response.ContentType = meta?.Metadata?.MimeType ?? "application/octet-stream";
2022-02-08 23:52:01 +00:00
return meta;
}
private IEnumerable<RangeRequest> GetRanges(HttpRequest request, long totalSize)
{
foreach (var rangeHeader in request.Headers.Range)
{
if (string.IsNullOrEmpty(rangeHeader))
{
continue;
}
var ranges = rangeHeader.Replace("bytes=", string.Empty).Split(",");
foreach (var range in ranges)
{
var rangeValues = range.Split("-");
long? endByte = null, startByte = 0;
if (long.TryParse(rangeValues[1], out var endParsed))
endByte = endParsed;
if (long.TryParse(rangeValues[0], out var startParsed))
startByte = startParsed;
yield return new(totalSize, startByte, endByte);
}
}
2022-01-25 23:39:51 +00:00
}
2022-02-08 23:52:01 +00:00
}