// Copyright Epic Games, Inc. All Rights Reserved. using System.Net.Mime; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace HordeServer.Utilities { /// /// Class deriving from a FileResult that allows custom file types (used for zip file creation) /// public class CustomFileCallbackResult : FileResult { private readonly Func _callback; readonly string _fileName; readonly bool _inline; /// /// Constructor /// /// Default filename for the downloaded file /// Content type for the file /// Whether to display the file inline in the browser /// Callback used to write the data public CustomFileCallbackResult(string fileName, string mimeType, bool inline, Func callback) : base(mimeType) { _fileName = fileName; _inline = inline; _callback = callback; } /// /// Executes the action result /// /// The controller context /// public override Task ExecuteResultAsync(ActionContext context) { ContentDisposition contentDisposition = new ContentDisposition(); contentDisposition.Inline = _inline; contentDisposition.FileName = _fileName; context.HttpContext.Response.Headers["Content-Disposition"] = contentDisposition.ToString(); CustomFileCallbackResultExecutor executor = new CustomFileCallbackResultExecutor(context.HttpContext.RequestServices.GetRequiredService()); return executor.ExecuteAsync(context, this); } /// /// Exectutor for the custom FileResult /// private sealed class CustomFileCallbackResultExecutor : FileResultExecutorBase { /// /// Constructor /// /// The logger public CustomFileCallbackResultExecutor(ILoggerFactory loggerFactory) : base(CreateLogger(loggerFactory)) { } /// /// Executes a CustomFileResult callback /// /// The controller context /// The custom file result /// public Task ExecuteAsync(ActionContext context, CustomFileCallbackResult result) { SetHeadersAndLog(context, result, null, false); return result._callback(context.HttpContext.Response.Body, context); } } } /// /// Stream overriding CanSeek to false so the zip file plays nice with it. /// public class CustomBufferStream : MemoryStream { /// /// Always report unseekable. /// public override bool CanSeek => false; } }