aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/HttpServer/FileWriter.cs
diff options
context:
space:
mode:
authorBond_009 <bond.009@outlook.com>2019-07-28 23:53:19 +0200
committerBond_009 <bond.009@outlook.com>2019-08-09 22:36:20 +0200
commit9fff4b060e06569ca77636643901aa42767e318d (patch)
tree4ed04ce48a9c4cb00dbc548d272ffec75da1324f /Emby.Server.Implementations/HttpServer/FileWriter.cs
parent779f0c637f4c280561029535a5b2160f34813b53 (diff)
Replace custom code with Asp.Net Core code
Diffstat (limited to 'Emby.Server.Implementations/HttpServer/FileWriter.cs')
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs174
1 files changed, 107 insertions, 67 deletions
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index ec41cc0a9..2890cca7c 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -1,50 +1,43 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Net;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Server.Implementations.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
public class FileWriter : IHttpResult
{
- private readonly IStreamHelper _streamHelper;
- private ILogger Logger { get; set; }
- private readonly IFileSystem _fileSystem;
-
- private string RangeHeader { get; set; }
- private bool IsHeadRequest { get; set; }
-
- private long RangeStart { get; set; }
- private long RangeEnd { get; set; }
- private long RangeLength { get; set; }
- public long TotalContentLength { get; set; }
+ private static readonly CultureInfo UsCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
- public Action OnComplete { get; set; }
- public Action OnError { get; set; }
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- public List<Cookie> Cookies { get; private set; }
+ private static readonly string[] _skipLogExtensions = {
+ ".js",
+ ".html",
+ ".css"
+ };
- public FileShareMode FileShare { get; set; }
+ private readonly IStreamHelper _streamHelper;
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// The _options
/// </summary>
private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
+
/// <summary>
- /// Gets the options.
+ /// The _requested ranges
/// </summary>
- /// <value>The options.</value>
- public IDictionary<string, string> Headers => _options;
-
- public string Path { get; set; }
+ private List<KeyValuePair<long, long?>> _requestedRanges;
public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper)
{
@@ -57,7 +50,7 @@ namespace Emby.Server.Implementations.HttpServer
_fileSystem = fileSystem;
Path = path;
- Logger = logger;
+ _logger = logger;
RangeHeader = rangeHeader;
Headers[HeaderNames.ContentType] = contentType;
@@ -80,39 +73,34 @@ namespace Emby.Server.Implementations.HttpServer
Cookies = new List<Cookie>();
}
- /// <summary>
- /// Sets the range values.
- /// </summary>
- private void SetRangeValues()
- {
- var requestedRange = RequestedRanges[0];
+ private string RangeHeader { get; set; }
- // If the requested range is "0-", we can optimize by just doing a stream copy
- if (!requestedRange.Value.HasValue)
- {
- RangeEnd = TotalContentLength - 1;
- }
- else
- {
- RangeEnd = requestedRange.Value.Value;
- }
+ private bool IsHeadRequest { get; set; }
- RangeStart = requestedRange.Key;
- RangeLength = 1 + RangeEnd - RangeStart;
+ private long RangeStart { get; set; }
- // Content-Length is the length of what we're serving, not the original content
- var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
- Headers[HeaderNames.ContentLength] = lengthString;
- var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
- Headers[HeaderNames.ContentRange] = rangeString;
+ private long RangeEnd { get; set; }
- Logger.LogDebug("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
- }
+ private long RangeLength { get; set; }
+
+ public long TotalContentLength { get; set; }
+
+ public Action OnComplete { get; set; }
+
+ public Action OnError { get; set; }
+
+ public List<Cookie> Cookies { get; private set; }
+
+ public FileShareMode FileShare { get; set; }
/// <summary>
- /// The _requested ranges
+ /// Gets the options.
/// </summary>
- private List<KeyValuePair<long, long?>> _requestedRanges;
+ /// <value>The options.</value>
+ public IDictionary<string, string> Headers => _options;
+
+ public string Path { get; set; }
+
/// <summary>
/// Gets the requested ranges.
/// </summary>
@@ -139,6 +127,7 @@ namespace Emby.Server.Implementations.HttpServer
{
start = long.Parse(vals[0], UsCulture);
}
+
if (!string.IsNullOrEmpty(vals[1]))
{
end = long.Parse(vals[1], UsCulture);
@@ -152,13 +141,50 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- private static readonly string[] SkipLogExtensions = {
- ".js",
- ".html",
- ".css"
- };
+ public string ContentType { get; set; }
+
+ public IRequest RequestContext { get; set; }
+
+ public object Response { get; set; }
+
+ public int Status { get; set; }
+
+ public HttpStatusCode StatusCode
+ {
+ get => (HttpStatusCode)Status;
+ set => Status = (int)value;
+ }
+
+ /// <summary>
+ /// Sets the range values.
+ /// </summary>
+ private void SetRangeValues()
+ {
+ var requestedRange = RequestedRanges[0];
+
+ // If the requested range is "0-", we can optimize by just doing a stream copy
+ if (!requestedRange.Value.HasValue)
+ {
+ RangeEnd = TotalContentLength - 1;
+ }
+ else
+ {
+ RangeEnd = requestedRange.Value.Value;
+ }
+
+ RangeStart = requestedRange.Key;
+ RangeLength = 1 + RangeEnd - RangeStart;
+
+ // Content-Length is the length of what we're serving, not the original content
+ var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
+ Headers[HeaderNames.ContentLength] = lengthString;
+ var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
+ Headers[HeaderNames.ContentRange] = rangeString;
- public async Task WriteToAsync(IResponse response, CancellationToken cancellationToken)
+ _logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
+ }
+
+ public async Task WriteToAsync(HttpResponse response, CancellationToken cancellationToken)
{
try
{
@@ -176,16 +202,16 @@ namespace Emby.Server.Implementations.HttpServer
{
var extension = System.IO.Path.GetExtension(path);
- if (extension == null || !SkipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+ if (extension == null || !_skipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
- Logger.LogDebug("Transmit file {0}", path);
+ _logger.LogDebug("Transmit file {0}", path);
}
offset = 0;
count = 0;
}
- await response.TransmitFile(path, offset, count, FileShare, _fileSystem, _streamHelper, cancellationToken).ConfigureAwait(false);
+ await TransmitFile(response.Body, path, offset, count, FileShare, cancellationToken).ConfigureAwait(false);
}
finally
{
@@ -193,18 +219,32 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- public string ContentType { get; set; }
-
- public IRequest RequestContext { get; set; }
+ public async Task TransmitFile(Stream stream, string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ {
+ var fileOpenOptions = FileOpenOptions.SequentialScan;
- public object Response { get; set; }
+ // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ fileOpenOptions |= FileOpenOptions.Asynchronous;
+ }
- public int Status { get; set; }
+ using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
+ {
+ if (offset > 0)
+ {
+ fs.Position = offset;
+ }
- public HttpStatusCode StatusCode
- {
- get => (HttpStatusCode)Status;
- set => Status = (int)value;
+ if (count > 0)
+ {
+ await _streamHelper.CopyToAsync(fs, stream, count, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await fs.CopyToAsync(stream, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
+ }
+ }
}
}
}