using System.Linq; using System.Threading.Tasks; using gehGassi.Core.Interfaces; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Primitives; namespace gehGassi.Web.Controllers { /// /// Controller für die Rückgabe von Dateien, Bilder usw. /// [Route("File")] public class FileController : Controller { private readonly IFileService _fileService; private readonly IFileShareService _fileShareService; private readonly IWebHostEnvironment _webHostEnvironment; /// /// Erstellt eine Instanz /// /// Instanz eines IFileService /// Instnanz eines IFileShareService /// Instanz eines IWebHostEnvironment public FileController(IFileService fileService, IFileShareService fileShareService, IWebHostEnvironment webHostEnvironment) { _fileService = fileService; _fileShareService = fileShareService; _webHostEnvironment = webHostEnvironment; } /// /// Gibt eine Datei zurück /// /// Container /// Dateiname inkl. Pfad (relativ) /// Datei oder notFound [HttpGet("{container}/{*filename}")] [ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "container", "filename" }, Location = ResponseCacheLocation.Any)] //[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public async Task GetFile(string container, string filename) { if (!string.IsNullOrWhiteSpace(container) && !string.IsNullOrWhiteSpace(filename)) { var file = await _fileService.GetAsync(container, filename); var flatFilename = _fileService.GetFlatFilename(filename); if (file != null) { return File(file, GetMimeMapping(flatFilename)); } } return NotFound(); } /// /// Gibt eine Datei zurück /// /// Container /// Dateiname inkl. Pfad (relativ) /// Datei oder notFound [HttpGet("uncached/{container}/{*filename}")] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public async Task GetFileUncached(string container, string filename) { var file = await _fileService.GetAsync(container, filename); var flatFilename = _fileService.GetFlatFilename(filename); if (file != null) { return File(file, GetMimeMapping(flatFilename)); } return NotFound(); } /// /// Gibt eine Datei zurück /// /// Share des Mandanten /// Dateiname inkl. Pfad (relativ) /// Datei oder notFound [ApiExplorerSettings(IgnoreApi = true)] [Route("~/Browser/", Name = "Browser")] [HttpGet("share/{share}/{*path}")] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Browser(string share, string path) { path = path.TrimStart('/'); var file = _fileShareService.Get(share, path); var flatFilename = path.Split('/').Last(); if (file != null) { return File(file, GetMimeMapping(flatFilename)); } return NotFound(); } /// /// Gibt ein Icon für eine Datei-Extension zurück /// /// Extenstion der Datei /// Datei oder notFound [HttpGet("extension/{*ext}")] [ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "ext" }, Location = ResponseCacheLocation.Any)] //[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Extension(string ext) { if (ext.Contains('.')) ext = ext.Replace(".", ""); var imageUrl = "/images/FileExtensions/_blank.png"; if (!string.IsNullOrEmpty(ext)) { imageUrl = "/images/FileExtensions/" + ext + ".png"; var absolutePath = _webHostEnvironment.WebRootPath + imageUrl; if (!System.IO.File.Exists(absolutePath)) { imageUrl = "/images/FileExtensions/_blank.png"; } } var file = System.IO.File.ReadAllBytes(_webHostEnvironment.WebRootPath + imageUrl); return File(file, GetMimeMapping(imageUrl)); } /// /// Gibt eine Datei zurück /// /// Share des Mandanten /// Dateiname inkl. Pfad (relativ) /// Datei oder notFound [Route("/scorm/{share}/{*path}", Name = "Scorm")] [HttpGet] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult GetScorm(string share, string path) { if (User.Identity.IsAuthenticated) { path = path.TrimStart('/'); var rangeHeader = Request.Headers["Range"]; if (rangeHeader.Count == 0) { var fileStream = _fileShareService.GetStream(share, path); var flatFilename = path.Split('/').Last(); if (fileStream != null) { return File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true); } } else { var info = _fileShareService.GetFileInfo(share, path); if (info != null) { var totalLength = info.Size; long start = 0; long end = 0; start = GetRangeStartAndEnd(rangeHeader, start, totalLength, ref end); long chunkSize = (end - start) + 1; var flatFilename = path.Split('/').Last(); var fileStream = _fileShareService.GetStream(share, path, start, end); if (fileStream != null) { var result = File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true); HttpContext.Response.Headers.ContentLength = chunkSize; HttpContext.Response.Headers.ContentType = GetMimeMapping(flatFilename); HttpContext.Response.Headers.ContentRange = $"bytes {start}-{end}/{totalLength}"; HttpContext.Response.Headers.AcceptRanges = "bytes"; HttpContext.Response.StatusCode = 206; return result; //return new FileStreamResult(fileStream, GetMimeMapping(flatFilename)); } } } } return NotFound(); } /// /// Gibt eine Video-Datei zurück /// /// Share des Mandanten /// Dateiname inkl. Pfad (relativ) /// Datei oder notFound [Route("/video/{share}/{*path}", Name = "Video")] [HttpGet] [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult GetVideo(string share, string path) { if (User.Identity.IsAuthenticated) { path = path.TrimStart('/'); var rangeHeader = Request.Headers["Range"]; if (rangeHeader.Count == 0) { var fileStream = _fileShareService.GetStream(share, path); var flatFilename = path.Split('/').Last(); if (fileStream != null) { return File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true); } } else { var info = _fileShareService.GetFileInfo(share, path); if (info != null) { var totalLength = info.Size; long start = 0; long end = 0; start = GetRangeStartAndEnd(rangeHeader, start, totalLength, ref end); long chunkSize = (end - start) + 1; var flatFilename = path.Split('/').Last(); var fileStream = _fileShareService.GetStream(share, path, start, end); if (fileStream != null) { var result = File(fileStream, GetMimeMapping(flatFilename), enableRangeProcessing: true); HttpContext.Response.Headers.ContentLength = chunkSize; HttpContext.Response.Headers.ContentType = GetMimeMapping(flatFilename); HttpContext.Response.Headers.ContentRange = $"bytes {start}-{end}/{totalLength}"; HttpContext.Response.Headers.AcceptRanges = "bytes"; HttpContext.Response.StatusCode = 206; return result; //return new FileStreamResult(fileStream, GetMimeMapping(flatFilename)); } } } } return NotFound(); } private static long GetRangeStartAndEnd(StringValues rangeHeader, long start, long totalLength, ref long end) { var headerContent = rangeHeader[0]; if (headerContent.StartsWith("bytes=")) { headerContent = headerContent.Replace("bytes=", ""); if (headerContent.EndsWith("-")) { headerContent = headerContent.Replace("-", ""); start = long.Parse(headerContent); end = totalLength - 1; } else { var parts = headerContent.Split("-"); start = long.Parse(parts[0]); end = long.Parse(parts[1]); } } return start; } /// /// Gibt den Mimetype einer Datei zurück /// /// Dateiname /// Mimetype private string GetMimeMapping(string fileName) { new FileExtensionContentTypeProvider().TryGetContentType(fileName, out var contentType); return contentType ?? "application/octet-stream"; } } }