| | | 1 | | using Elsa.Http.Abstractions; |
| | | 2 | | using Elsa.Http.Contexts; |
| | | 3 | | using Elsa.Http.Options; |
| | | 4 | | using Microsoft.AspNetCore.StaticFiles; |
| | | 5 | | |
| | | 6 | | namespace Elsa.Http.DownloadableContentHandlers; |
| | | 7 | | |
| | | 8 | | /// <summary> |
| | | 9 | | /// Handles content that represents a downloadable URL. |
| | | 10 | | /// </summary> |
| | | 11 | | public class UrlDownloadableContentHandler : DownloadableContentHandlerBase |
| | | 12 | | { |
| | | 13 | | private readonly IFileDownloader _fileDownloader; |
| | | 14 | | private readonly IContentTypeProvider _contentTypeProvider; |
| | | 15 | | |
| | | 16 | | /// <inheritdoc /> |
| | 0 | 17 | | public UrlDownloadableContentHandler(IFileDownloader fileDownloader, IContentTypeProvider contentTypeProvider) |
| | | 18 | | { |
| | 0 | 19 | | _fileDownloader = fileDownloader; |
| | 0 | 20 | | _contentTypeProvider = contentTypeProvider; |
| | 0 | 21 | | } |
| | | 22 | | |
| | | 23 | | /// <inheritdoc /> |
| | 0 | 24 | | public override bool GetSupportsContent(object content) => (content is string url && url.StartsWith("http", StringCo |
| | | 25 | | |
| | | 26 | | /// <inheritdoc /> |
| | 0 | 27 | | protected override Func<ValueTask<Downloadable>> GetDownloadableAsync(DownloadableContext context) => async () => aw |
| | | 28 | | |
| | | 29 | | private async ValueTask<Downloadable> DownloadAsync(DownloadableContext context) |
| | | 30 | | { |
| | 0 | 31 | | var url = context.Content is string s ? new Uri(s) : (Uri)context.Content; |
| | 0 | 32 | | var cancellationToken = context.CancellationToken; |
| | 0 | 33 | | var options = new FileDownloadOptions |
| | 0 | 34 | | { |
| | 0 | 35 | | // TODO: Uncomment the next two lines if we implement file caching for this handler. |
| | 0 | 36 | | // ETag = context.Options.ETag, |
| | 0 | 37 | | // Range = context.Options.Range |
| | 0 | 38 | | }; |
| | 0 | 39 | | var response = await _fileDownloader.DownloadAsync(url, options, cancellationToken); |
| | 0 | 40 | | var eTag = response.Headers.ETag?.Tag; |
| | 0 | 41 | | var filename = GetFilename(response) ?? url.Segments.Last(); |
| | 0 | 42 | | var contentType = response.Content.Headers.ContentType?.MediaType ?? GetContentType(filename); |
| | 0 | 43 | | var stream = await response.Content.ReadAsStreamAsync(cancellationToken); |
| | | 44 | | |
| | 0 | 45 | | return new Downloadable(stream, filename, contentType, eTag); |
| | 0 | 46 | | } |
| | | 47 | | |
| | | 48 | | private static string? GetFilename(HttpResponseMessage response) |
| | | 49 | | { |
| | 0 | 50 | | if (!response.Content.Headers.TryGetValues("Content-Disposition", out var values)) |
| | 0 | 51 | | return null; |
| | | 52 | | |
| | 0 | 53 | | var contentDispositionString = string.Join("", values); |
| | 0 | 54 | | var contentDisposition = new System.Net.Mime.ContentDisposition(contentDispositionString); |
| | 0 | 55 | | return contentDisposition.FileName; |
| | | 56 | | } |
| | | 57 | | |
| | | 58 | | private string GetContentType(string filename) |
| | | 59 | | { |
| | 0 | 60 | | return _contentTypeProvider.TryGetContentType(filename, out var contentType) ? contentType : System.Net.Mime.Med |
| | | 61 | | } |
| | | 62 | | } |