aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener.Portable/Net/ResponseStream.cs
diff options
context:
space:
mode:
Diffstat (limited to 'SocketHttpListener.Portable/Net/ResponseStream.cs')
-rw-r--r--SocketHttpListener.Portable/Net/ResponseStream.cs84
1 files changed, 83 insertions, 1 deletions
diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs
index a79a18791..3c79f47c2 100644
--- a/SocketHttpListener.Portable/Net/ResponseStream.cs
+++ b/SocketHttpListener.Portable/Net/ResponseStream.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
@@ -22,12 +23,18 @@ namespace SocketHttpListener.Net
Stream stream;
private readonly IMemoryStreamFactory _memoryStreamFactory;
private readonly ITextEncoding _textEncoding;
+ private readonly IFileSystem _fileSystem;
+ private readonly IAcceptSocket _socket;
+ private readonly bool _supportsDirectSocketAccess;
- internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding)
+ internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess)
{
this.response = response;
_memoryStreamFactory = memoryStreamFactory;
_textEncoding = textEncoding;
+ _fileSystem = fileSystem;
+ _socket = socket;
+ _supportsDirectSocketAccess = supportsDirectSocketAccess;
this.stream = stream;
}
@@ -299,5 +306,80 @@ namespace SocketHttpListener.Net
{
throw new NotSupportedException();
}
+
+ public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ {
+ //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked)
+ //{
+ // return TransmitFileOverSocket(path, offset, count, cancellationToken);
+ //}
+ return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
+ }
+
+ private readonly byte[] _emptyBuffer = new byte[] { };
+ private async Task TransmitFileOverSocket(string path, long offset, long count, CancellationToken cancellationToken)
+ {
+ MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
+
+ var buffer = new byte[] {};
+ if (ms != null)
+ {
+ ms.Position = 0;
+
+ byte[] msBuffer;
+ _memoryStreamFactory.TryGetBuffer(ms, out msBuffer);
+ buffer = msBuffer;
+ }
+
+ await _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken).ConfigureAwait(false);
+ }
+
+ private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ {
+ var chunked = response.SendChunked;
+
+ if (!chunked)
+ {
+ await WriteAsync(_emptyBuffer, 0, 0, cancellationToken).ConfigureAwait(false);
+ }
+
+ using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, true))
+ {
+ if (offset > 0)
+ {
+ fs.Position = offset;
+ }
+
+ var targetStream = chunked ? this : stream;
+
+ if (count > 0)
+ {
+ await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await fs.CopyToAsync(targetStream, 81920, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ }
+
+ private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
+ {
+ var array = new byte[81920];
+ int count;
+ while ((count = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
+ {
+ var bytesToCopy = Math.Min(count, copyLength);
+
+ await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy), cancellationToken).ConfigureAwait(false);
+
+ copyLength -= bytesToCopy;
+
+ if (copyLength <= 0)
+ {
+ break;
+ }
+ }
+ }
}
}