From f07af448fa11330db93dd7ddcabac37ef9e014c7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 24 May 2017 15:12:55 -0400 Subject: update main projects --- .../Net/AuthenticationSchemeSelector.cs | 6 + SocketHttpListener/Net/ChunkStream.cs | 405 +++++++++++++ SocketHttpListener/Net/ChunkedInputStream.cs | 172 ++++++ SocketHttpListener/Net/CookieHelper.cs | 144 +++++ SocketHttpListener/Net/EndPointListener.cs | 391 ++++++++++++ SocketHttpListener/Net/EndPointManager.cs | 166 ++++++ SocketHttpListener/Net/HttpConnection.cs | 547 +++++++++++++++++ SocketHttpListener/Net/HttpListener.cs | 293 +++++++++ .../Net/HttpListenerBasicIdentity.cs | 70 +++ SocketHttpListener/Net/HttpListenerContext.cs | 198 +++++++ .../Net/HttpListenerPrefixCollection.cs | 97 +++ SocketHttpListener/Net/HttpListenerRequest.cs | 654 +++++++++++++++++++++ SocketHttpListener/Net/HttpListenerResponse.cs | 525 +++++++++++++++++ .../Net/HttpRequestStream.Managed.cs | 196 ++++++ SocketHttpListener/Net/HttpRequestStream.cs | 144 +++++ SocketHttpListener/Net/HttpStatusCode.cs | 321 ++++++++++ SocketHttpListener/Net/HttpStreamAsyncResult.cs | 85 +++ SocketHttpListener/Net/HttpVersion.cs | 16 + SocketHttpListener/Net/ListenerPrefix.cs | 148 +++++ SocketHttpListener/Net/ResponseStream.cs | 400 +++++++++++++ SocketHttpListener/Net/WebHeaderCollection.cs | 391 ++++++++++++ .../Net/WebSockets/HttpListenerWebSocketContext.cs | 348 +++++++++++ .../Net/WebSockets/WebSocketContext.cs | 183 ++++++ 23 files changed, 5900 insertions(+) create mode 100644 SocketHttpListener/Net/AuthenticationSchemeSelector.cs create mode 100644 SocketHttpListener/Net/ChunkStream.cs create mode 100644 SocketHttpListener/Net/ChunkedInputStream.cs create mode 100644 SocketHttpListener/Net/CookieHelper.cs create mode 100644 SocketHttpListener/Net/EndPointListener.cs create mode 100644 SocketHttpListener/Net/EndPointManager.cs create mode 100644 SocketHttpListener/Net/HttpConnection.cs create mode 100644 SocketHttpListener/Net/HttpListener.cs create mode 100644 SocketHttpListener/Net/HttpListenerBasicIdentity.cs create mode 100644 SocketHttpListener/Net/HttpListenerContext.cs create mode 100644 SocketHttpListener/Net/HttpListenerPrefixCollection.cs create mode 100644 SocketHttpListener/Net/HttpListenerRequest.cs create mode 100644 SocketHttpListener/Net/HttpListenerResponse.cs create mode 100644 SocketHttpListener/Net/HttpRequestStream.Managed.cs create mode 100644 SocketHttpListener/Net/HttpRequestStream.cs create mode 100644 SocketHttpListener/Net/HttpStatusCode.cs create mode 100644 SocketHttpListener/Net/HttpStreamAsyncResult.cs create mode 100644 SocketHttpListener/Net/HttpVersion.cs create mode 100644 SocketHttpListener/Net/ListenerPrefix.cs create mode 100644 SocketHttpListener/Net/ResponseStream.cs create mode 100644 SocketHttpListener/Net/WebHeaderCollection.cs create mode 100644 SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs create mode 100644 SocketHttpListener/Net/WebSockets/WebSocketContext.cs (limited to 'SocketHttpListener/Net') diff --git a/SocketHttpListener/Net/AuthenticationSchemeSelector.cs b/SocketHttpListener/Net/AuthenticationSchemeSelector.cs new file mode 100644 index 000000000..c6e7e538e --- /dev/null +++ b/SocketHttpListener/Net/AuthenticationSchemeSelector.cs @@ -0,0 +1,6 @@ +using System.Net; + +namespace SocketHttpListener.Net +{ + public delegate AuthenticationSchemes AuthenticationSchemeSelector(HttpListenerRequest httpRequest); +} diff --git a/SocketHttpListener/Net/ChunkStream.cs b/SocketHttpListener/Net/ChunkStream.cs new file mode 100644 index 000000000..2de6c2c18 --- /dev/null +++ b/SocketHttpListener/Net/ChunkStream.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; + +namespace SocketHttpListener.Net +{ + // Licensed to the .NET Foundation under one or more agreements. + // See the LICENSE file in the project root for more information. + // + // System.Net.ResponseStream + // + // Author: + // Gonzalo Paniagua Javier (gonzalo@novell.com) + // + // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + // + // Permission is hereby granted, free of charge, to any person obtaining + // a copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + // + // The above copyright notice and this permission notice shall be + // included in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + // + + internal sealed class ChunkStream + { + private enum State + { + None, + PartialSize, + Body, + BodyFinished, + Trailer + } + + private class Chunk + { + public byte[] Bytes; + public int Offset; + + public Chunk(byte[] chunk) + { + Bytes = chunk; + } + + public int Read(byte[] buffer, int offset, int size) + { + int nread = (size > Bytes.Length - Offset) ? Bytes.Length - Offset : size; + Buffer.BlockCopy(Bytes, Offset, buffer, offset, nread); + Offset += nread; + return nread; + } + } + + internal WebHeaderCollection _headers; + private int _chunkSize; + private int _chunkRead; + private int _totalWritten; + private State _state; + private StringBuilder _saved; + private bool _sawCR; + private bool _gotit; + private int _trailerState; + private List _chunks; + + public ChunkStream(byte[] buffer, int offset, int size, WebHeaderCollection headers) + : this(headers) + { + Write(buffer, offset, size); + } + + public ChunkStream(WebHeaderCollection headers) + { + _headers = headers; + _saved = new StringBuilder(); + _chunks = new List(); + _chunkSize = -1; + _totalWritten = 0; + } + + public void ResetBuffer() + { + _chunkSize = -1; + _chunkRead = 0; + _totalWritten = 0; + _chunks.Clear(); + } + + public void WriteAndReadBack(byte[] buffer, int offset, int size, ref int read) + { + if (offset + read > 0) + Write(buffer, offset, offset + read); + read = Read(buffer, offset, size); + } + + public int Read(byte[] buffer, int offset, int size) + { + return ReadFromChunks(buffer, offset, size); + } + + private int ReadFromChunks(byte[] buffer, int offset, int size) + { + int count = _chunks.Count; + int nread = 0; + + var chunksForRemoving = new List(count); + for (int i = 0; i < count; i++) + { + Chunk chunk = _chunks[i]; + + if (chunk.Offset == chunk.Bytes.Length) + { + chunksForRemoving.Add(chunk); + continue; + } + + nread += chunk.Read(buffer, offset + nread, size - nread); + if (nread == size) + break; + } + + foreach (var chunk in chunksForRemoving) + _chunks.Remove(chunk); + + return nread; + } + + public void Write(byte[] buffer, int offset, int size) + { + if (offset < size) + InternalWrite(buffer, ref offset, size); + } + + private void InternalWrite(byte[] buffer, ref int offset, int size) + { + if (_state == State.None || _state == State.PartialSize) + { + _state = GetChunkSize(buffer, ref offset, size); + if (_state == State.PartialSize) + return; + + _saved.Length = 0; + _sawCR = false; + _gotit = false; + } + + if (_state == State.Body && offset < size) + { + _state = ReadBody(buffer, ref offset, size); + if (_state == State.Body) + return; + } + + if (_state == State.BodyFinished && offset < size) + { + _state = ReadCRLF(buffer, ref offset, size); + if (_state == State.BodyFinished) + return; + + _sawCR = false; + } + + if (_state == State.Trailer && offset < size) + { + _state = ReadTrailer(buffer, ref offset, size); + if (_state == State.Trailer) + return; + + _saved.Length = 0; + _sawCR = false; + _gotit = false; + } + + if (offset < size) + InternalWrite(buffer, ref offset, size); + } + + public bool WantMore + { + get { return (_chunkRead != _chunkSize || _chunkSize != 0 || _state != State.None); } + } + + public bool DataAvailable + { + get + { + int count = _chunks.Count; + for (int i = 0; i < count; i++) + { + Chunk ch = _chunks[i]; + if (ch == null || ch.Bytes == null) + continue; + if (ch.Bytes.Length > 0 && ch.Offset < ch.Bytes.Length) + return (_state != State.Body); + } + return false; + } + } + + public int TotalDataSize + { + get { return _totalWritten; } + } + + public int ChunkLeft + { + get { return _chunkSize - _chunkRead; } + } + + private State ReadBody(byte[] buffer, ref int offset, int size) + { + if (_chunkSize == 0) + return State.BodyFinished; + + int diff = size - offset; + if (diff + _chunkRead > _chunkSize) + diff = _chunkSize - _chunkRead; + + byte[] chunk = new byte[diff]; + Buffer.BlockCopy(buffer, offset, chunk, 0, diff); + _chunks.Add(new Chunk(chunk)); + offset += diff; + _chunkRead += diff; + _totalWritten += diff; + + return (_chunkRead == _chunkSize) ? State.BodyFinished : State.Body; + } + + private State GetChunkSize(byte[] buffer, ref int offset, int size) + { + _chunkRead = 0; + _chunkSize = 0; + char c = '\0'; + while (offset < size) + { + c = (char)buffer[offset++]; + if (c == '\r') + { + if (_sawCR) + ThrowProtocolViolation("2 CR found"); + + _sawCR = true; + continue; + } + + if (_sawCR && c == '\n') + break; + + if (c == ' ') + _gotit = true; + + if (!_gotit) + _saved.Append(c); + + if (_saved.Length > 20) + ThrowProtocolViolation("chunk size too long."); + } + + if (!_sawCR || c != '\n') + { + if (offset < size) + ThrowProtocolViolation("Missing \\n"); + + try + { + if (_saved.Length > 0) + { + _chunkSize = Int32.Parse(RemoveChunkExtension(_saved.ToString()), NumberStyles.HexNumber); + } + } + catch (Exception) + { + ThrowProtocolViolation("Cannot parse chunk size."); + } + + return State.PartialSize; + } + + _chunkRead = 0; + try + { + _chunkSize = Int32.Parse(RemoveChunkExtension(_saved.ToString()), NumberStyles.HexNumber); + } + catch (Exception) + { + ThrowProtocolViolation("Cannot parse chunk size."); + } + + if (_chunkSize == 0) + { + _trailerState = 2; + return State.Trailer; + } + + return State.Body; + } + + private static string RemoveChunkExtension(string input) + { + int idx = input.IndexOf(';'); + if (idx == -1) + return input; + return input.Substring(0, idx); + } + + private State ReadCRLF(byte[] buffer, ref int offset, int size) + { + if (!_sawCR) + { + if ((char)buffer[offset++] != '\r') + ThrowProtocolViolation("Expecting \\r"); + + _sawCR = true; + if (offset == size) + return State.BodyFinished; + } + + if (_sawCR && (char)buffer[offset++] != '\n') + ThrowProtocolViolation("Expecting \\n"); + + return State.None; + } + + private State ReadTrailer(byte[] buffer, ref int offset, int size) + { + char c = '\0'; + + // short path + if (_trailerState == 2 && (char)buffer[offset] == '\r' && _saved.Length == 0) + { + offset++; + if (offset < size && (char)buffer[offset] == '\n') + { + offset++; + return State.None; + } + offset--; + } + + int st = _trailerState; + string stString = "\r\n\r"; + while (offset < size && st < 4) + { + c = (char)buffer[offset++]; + if ((st == 0 || st == 2) && c == '\r') + { + st++; + continue; + } + + if ((st == 1 || st == 3) && c == '\n') + { + st++; + continue; + } + + if (st > 0) + { + _saved.Append(stString.Substring(0, _saved.Length == 0 ? st - 2 : st)); + st = 0; + if (_saved.Length > 4196) + ThrowProtocolViolation("Error reading trailer (too long)."); + } + } + + if (st < 4) + { + _trailerState = st; + if (offset < size) + ThrowProtocolViolation("Error reading trailer."); + + return State.Trailer; + } + + StringReader reader = new StringReader(_saved.ToString()); + string line; + while ((line = reader.ReadLine()) != null && line != "") + _headers.Add(line); + + return State.None; + } + + private static void ThrowProtocolViolation(string message) + { + WebException we = new WebException(message, null, WebExceptionStatus.ServerProtocolViolation, null); + throw we; + } + } +} diff --git a/SocketHttpListener/Net/ChunkedInputStream.cs b/SocketHttpListener/Net/ChunkedInputStream.cs new file mode 100644 index 000000000..2e0e1964b --- /dev/null +++ b/SocketHttpListener/Net/ChunkedInputStream.cs @@ -0,0 +1,172 @@ +using System; +using System.IO; +using System.Net; +using System.Runtime.InteropServices; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + // Licensed to the .NET Foundation under one or more agreements. + // See the LICENSE file in the project root for more information. + // + // System.Net.ResponseStream + // + // Author: + // Gonzalo Paniagua Javier (gonzalo@novell.com) + // + // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + // + // Permission is hereby granted, free of charge, to any person obtaining + // a copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + // + // The above copyright notice and this permission notice shall be + // included in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + // + + internal sealed class ChunkedInputStream : HttpRequestStream + { + private ChunkStream _decoder; + private readonly HttpListenerContext _context; + private bool _no_more_data; + + private class ReadBufferState + { + public byte[] Buffer; + public int Offset; + public int Count; + public int InitialCount; + public HttpStreamAsyncResult Ares; + public ReadBufferState(byte[] buffer, int offset, int count, HttpStreamAsyncResult ares) + { + Buffer = buffer; + Offset = offset; + Count = count; + InitialCount = count; + Ares = ares; + } + } + + public ChunkedInputStream(HttpListenerContext context, Stream stream, byte[] buffer, int offset, int length) + : base(stream, buffer, offset, length) + { + _context = context; + WebHeaderCollection coll = (WebHeaderCollection)context.Request.Headers; + _decoder = new ChunkStream(coll); + } + + public ChunkStream Decoder + { + get { return _decoder; } + set { _decoder = value; } + } + + protected override int ReadCore(byte[] buffer, int offset, int count) + { + IAsyncResult ares = BeginReadCore(buffer, offset, count, null, null); + return EndRead(ares); + } + + protected override IAsyncResult BeginReadCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state) + { + HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this); + ares._callback = cback; + ares._state = state; + if (_no_more_data || size == 0 || _closed) + { + ares.Complete(); + return ares; + } + int nread = _decoder.Read(buffer, offset, size); + offset += nread; + size -= nread; + if (size == 0) + { + // got all we wanted, no need to bother the decoder yet + ares._count = nread; + ares.Complete(); + return ares; + } + if (!_decoder.WantMore) + { + _no_more_data = nread == 0; + ares._count = nread; + ares.Complete(); + return ares; + } + ares._buffer = new byte[8192]; + ares._offset = 0; + ares._count = 8192; + ReadBufferState rb = new ReadBufferState(buffer, offset, size, ares); + rb.InitialCount += nread; + base.BeginReadCore(ares._buffer, ares._offset, ares._count, OnRead, rb); + return ares; + } + + private void OnRead(IAsyncResult base_ares) + { + ReadBufferState rb = (ReadBufferState)base_ares.AsyncState; + HttpStreamAsyncResult ares = rb.Ares; + try + { + int nread = base.EndRead(base_ares); + _decoder.Write(ares._buffer, ares._offset, nread); + nread = _decoder.Read(rb.Buffer, rb.Offset, rb.Count); + rb.Offset += nread; + rb.Count -= nread; + if (rb.Count == 0 || !_decoder.WantMore || nread == 0) + { + _no_more_data = !_decoder.WantMore && nread == 0; + ares._count = rb.InitialCount - rb.Count; + ares.Complete(); + return; + } + ares._offset = 0; + ares._count = Math.Min(8192, _decoder.ChunkLeft + 6); + base.BeginReadCore(ares._buffer, ares._offset, ares._count, OnRead, rb); + } + catch (Exception e) + { + _context.Connection.SendError(e.Message, 400); + ares.Complete(e); + } + } + + public override int EndRead(IAsyncResult asyncResult) + { + if (asyncResult == null) + throw new ArgumentNullException(nameof(asyncResult)); + + HttpStreamAsyncResult ares = asyncResult as HttpStreamAsyncResult; + if (ares == null || !ReferenceEquals(this, ares._parent)) + { + throw new ArgumentException("Invalid async result"); + } + if (ares._endCalled) + { + throw new InvalidOperationException("Invalid end call"); + } + ares._endCalled = true; + + if (!asyncResult.IsCompleted) + asyncResult.AsyncWaitHandle.WaitOne(); + + if (ares._error != null) + throw new HttpListenerException((int)HttpStatusCode.BadRequest, "Bad Request"); + + return ares._count; + } + } +} diff --git a/SocketHttpListener/Net/CookieHelper.cs b/SocketHttpListener/Net/CookieHelper.cs new file mode 100644 index 000000000..470507d6b --- /dev/null +++ b/SocketHttpListener/Net/CookieHelper.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace SocketHttpListener.Net +{ + public static class CookieHelper + { + internal static CookieCollection Parse(string value, bool response) + { + return response + ? parseResponse(value) + : null; + } + + private static string[] splitCookieHeaderValue(string value) + { + return new List(value.SplitHeaderValue(',', ';')).ToArray(); + } + + private static CookieCollection parseResponse(string value) + { + var cookies = new CookieCollection(); + + Cookie cookie = null; + var pairs = splitCookieHeaderValue(value); + for (int i = 0; i < pairs.Length; i++) + { + var pair = pairs[i].Trim(); + if (pair.Length == 0) + continue; + + if (pair.StartsWith("version", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.Version = Int32.Parse(pair.GetValueInternal("=").Trim('"')); + } + else if (pair.StartsWith("expires", StringComparison.OrdinalIgnoreCase)) + { + var buffer = new StringBuilder(pair.GetValueInternal("="), 32); + if (i < pairs.Length - 1) + buffer.AppendFormat(", {0}", pairs[++i].Trim()); + + DateTime expires; + if (!DateTime.TryParseExact( + buffer.ToString(), + new[] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" }, + new CultureInfo("en-US"), + DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, + out expires)) + expires = DateTime.Now; + + if (cookie != null && cookie.Expires == DateTime.MinValue) + cookie.Expires = expires.ToLocalTime(); + } + else if (pair.StartsWith("max-age", StringComparison.OrdinalIgnoreCase)) + { + var max = Int32.Parse(pair.GetValueInternal("=").Trim('"')); + var expires = DateTime.Now.AddSeconds((double)max); + if (cookie != null) + cookie.Expires = expires; + } + else if (pair.StartsWith("path", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.Path = pair.GetValueInternal("="); + } + else if (pair.StartsWith("domain", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.Domain = pair.GetValueInternal("="); + } + else if (pair.StartsWith("port", StringComparison.OrdinalIgnoreCase)) + { + var port = pair.Equals("port", StringComparison.OrdinalIgnoreCase) + ? "\"\"" + : pair.GetValueInternal("="); + + if (cookie != null) + cookie.Port = port; + } + else if (pair.StartsWith("comment", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.Comment = pair.GetValueInternal("=").UrlDecode(); + } + else if (pair.StartsWith("commenturl", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.CommentUri = pair.GetValueInternal("=").Trim('"').ToUri(); + } + else if (pair.StartsWith("discard", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.Discard = true; + } + else if (pair.StartsWith("secure", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.Secure = true; + } + else if (pair.StartsWith("httponly", StringComparison.OrdinalIgnoreCase)) + { + if (cookie != null) + cookie.HttpOnly = true; + } + else + { + if (cookie != null) + cookies.Add(cookie); + + string name; + string val = String.Empty; + + var pos = pair.IndexOf('='); + if (pos == -1) + { + name = pair; + } + else if (pos == pair.Length - 1) + { + name = pair.Substring(0, pos).TrimEnd(' '); + } + else + { + name = pair.Substring(0, pos).TrimEnd(' '); + val = pair.Substring(pos + 1).TrimStart(' '); + } + + cookie = new Cookie(name, val); + } + } + + if (cookie != null) + cookies.Add(cookie); + + return cookies; + } + } +} diff --git a/SocketHttpListener/Net/EndPointListener.cs b/SocketHttpListener/Net/EndPointListener.cs new file mode 100644 index 000000000..2106bbec5 --- /dev/null +++ b/SocketHttpListener/Net/EndPointListener.cs @@ -0,0 +1,391 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + sealed class EndPointListener + { + HttpListener listener; + IpEndPointInfo endpoint; + IAcceptSocket sock; + Dictionary prefixes; // Dictionary + List unhandled; // List unhandled; host = '*' + List all; // List all; host = '+' + ICertificate cert; + bool secure; + Dictionary unregistered; + private readonly ILogger _logger; + private bool _closed; + private bool _enableDualMode; + private readonly ICryptoProvider _cryptoProvider; + private readonly IStreamFactory _streamFactory; + private readonly ISocketFactory _socketFactory; + private readonly ITextEncoding _textEncoding; + private readonly IMemoryStreamFactory _memoryStreamFactory; + private readonly IFileSystem _fileSystem; + private readonly IEnvironmentInfo _environment; + + public EndPointListener(HttpListener listener, IpAddressInfo addr, int port, bool secure, ICertificate cert, ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + { + this.listener = listener; + _logger = logger; + _cryptoProvider = cryptoProvider; + _streamFactory = streamFactory; + _socketFactory = socketFactory; + _memoryStreamFactory = memoryStreamFactory; + _textEncoding = textEncoding; + _fileSystem = fileSystem; + _environment = environment; + + this.secure = secure; + this.cert = cert; + + _enableDualMode = addr.Equals(IpAddressInfo.IPv6Any); + endpoint = new IpEndPointInfo(addr, port); + + prefixes = new Dictionary(); + unregistered = new Dictionary(); + + CreateSocket(); + } + + internal HttpListener Listener + { + get + { + return listener; + } + } + + private void CreateSocket() + { + try + { + sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode); + } + catch (SocketCreateException ex) + { + if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && + (string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase) || + // mono on bsd is throwing this + string.Equals(ex.ErrorCode, "ProtocolNotSupported", StringComparison.OrdinalIgnoreCase))) + { + endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port); + _enableDualMode = false; + sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode); + } + else + { + throw; + } + } + + sock.Bind(endpoint); + + // This is the number TcpListener uses. + sock.Listen(2147483647); + + sock.StartAccept(ProcessAccept, () => _closed); + _closed = false; + } + + private async void ProcessAccept(IAcceptSocket accepted) + { + try + { + var listener = this; + + if (listener.secure && listener.cert == null) + { + accepted.Close(); + return; + } + + HttpConnection conn = await HttpConnection.Create(_logger, accepted, listener, listener.secure, listener.cert, _cryptoProvider, _streamFactory, _memoryStreamFactory, _textEncoding, _fileSystem, _environment).ConfigureAwait(false); + + //_logger.Debug("Adding unregistered connection to {0}. Id: {1}", accepted.RemoteEndPoint, connectionId); + lock (listener.unregistered) + { + listener.unregistered[conn] = conn; + } + conn.BeginReadRequest(); + } + catch (Exception ex) + { + _logger.ErrorException("Error in ProcessAccept", ex); + } + } + + internal void RemoveConnection(HttpConnection conn) + { + lock (unregistered) + { + unregistered.Remove(conn); + } + } + + public bool BindContext(HttpListenerContext context) + { + HttpListenerRequest req = context.Request; + ListenerPrefix prefix; + HttpListener listener = SearchListener(req.Url, out prefix); + if (listener == null) + return false; + + context.Connection.Prefix = prefix; + return true; + } + + public void UnbindContext(HttpListenerContext context) + { + if (context == null || context.Request == null) + return; + + listener.UnregisterContext(context); + } + + HttpListener SearchListener(Uri uri, out ListenerPrefix prefix) + { + prefix = null; + if (uri == null) + return null; + + string host = uri.Host; + int port = uri.Port; + string path = WebUtility.UrlDecode(uri.AbsolutePath); + string path_slash = path[path.Length - 1] == '/' ? path : path + "/"; + + HttpListener best_match = null; + int best_length = -1; + + if (host != null && host != "") + { + var p_ro = prefixes; + foreach (ListenerPrefix p in p_ro.Keys) + { + string ppath = p.Path; + if (ppath.Length < best_length) + continue; + + if (p.Host != host || p.Port != port) + continue; + + if (path.StartsWith(ppath) || path_slash.StartsWith(ppath)) + { + best_length = ppath.Length; + best_match = (HttpListener)p_ro[p]; + prefix = p; + } + } + if (best_length != -1) + return best_match; + } + + List list = unhandled; + best_match = MatchFromList(host, path, list, out prefix); + if (path != path_slash && best_match == null) + best_match = MatchFromList(host, path_slash, list, out prefix); + if (best_match != null) + return best_match; + + list = all; + best_match = MatchFromList(host, path, list, out prefix); + if (path != path_slash && best_match == null) + best_match = MatchFromList(host, path_slash, list, out prefix); + if (best_match != null) + return best_match; + + return null; + } + + HttpListener MatchFromList(string host, string path, List list, out ListenerPrefix prefix) + { + prefix = null; + if (list == null) + return null; + + HttpListener best_match = null; + int best_length = -1; + + foreach (ListenerPrefix p in list) + { + string ppath = p.Path; + if (ppath.Length < best_length) + continue; + + if (path.StartsWith(ppath)) + { + best_length = ppath.Length; + best_match = p.Listener; + prefix = p; + } + } + + return best_match; + } + + void AddSpecial(List coll, ListenerPrefix prefix) + { + if (coll == null) + return; + + foreach (ListenerPrefix p in coll) + { + if (p.Path == prefix.Path) //TODO: code + throw new HttpListenerException(400, "Prefix already in use."); + } + coll.Add(prefix); + } + + bool RemoveSpecial(List coll, ListenerPrefix prefix) + { + if (coll == null) + return false; + + int c = coll.Count; + for (int i = 0; i < c; i++) + { + ListenerPrefix p = (ListenerPrefix)coll[i]; + if (p.Path == prefix.Path) + { + coll.RemoveAt(i); + return true; + } + } + return false; + } + + void CheckIfRemove() + { + if (prefixes.Count > 0) + return; + + List list = unhandled; + if (list != null && list.Count > 0) + return; + + list = all; + if (list != null && list.Count > 0) + return; + + EndPointManager.RemoveEndPoint(this, endpoint); + } + + public void Close() + { + _closed = true; + sock.Close(); + lock (unregistered) + { + // + // Clone the list because RemoveConnection can be called from Close + // + var connections = new List(unregistered.Keys); + + foreach (HttpConnection c in connections) + c.Close(true); + unregistered.Clear(); + } + } + + public void AddPrefix(ListenerPrefix prefix, HttpListener listener) + { + List current; + List future; + if (prefix.Host == "*") + { + do + { + current = unhandled; + future = (current != null) ? current.ToList() : new List(); + prefix.Listener = listener; + AddSpecial(future, prefix); + } while (Interlocked.CompareExchange(ref unhandled, future, current) != current); + return; + } + + if (prefix.Host == "+") + { + do + { + current = all; + future = (current != null) ? current.ToList() : new List(); + prefix.Listener = listener; + AddSpecial(future, prefix); + } while (Interlocked.CompareExchange(ref all, future, current) != current); + return; + } + + Dictionary prefs; + Dictionary p2; + do + { + prefs = prefixes; + if (prefs.ContainsKey(prefix)) + { + HttpListener other = (HttpListener)prefs[prefix]; + if (other != listener) // TODO: code. + throw new HttpListenerException(400, "There's another listener for " + prefix); + return; + } + p2 = new Dictionary(prefs); + p2[prefix] = listener; + } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs); + } + + public void RemovePrefix(ListenerPrefix prefix, HttpListener listener) + { + List current; + List future; + if (prefix.Host == "*") + { + do + { + current = unhandled; + future = (current != null) ? current.ToList() : new List(); + if (!RemoveSpecial(future, prefix)) + break; // Prefix not found + } while (Interlocked.CompareExchange(ref unhandled, future, current) != current); + CheckIfRemove(); + return; + } + + if (prefix.Host == "+") + { + do + { + current = all; + future = (current != null) ? current.ToList() : new List(); + if (!RemoveSpecial(future, prefix)) + break; // Prefix not found + } while (Interlocked.CompareExchange(ref all, future, current) != current); + CheckIfRemove(); + return; + } + + Dictionary prefs; + Dictionary p2; + do + { + prefs = prefixes; + if (!prefs.ContainsKey(prefix)) + break; + + p2 = new Dictionary(prefs); + p2.Remove(prefix); + } while (Interlocked.CompareExchange(ref prefixes, p2, prefs) != prefs); + CheckIfRemove(); + } + } +} diff --git a/SocketHttpListener/Net/EndPointManager.cs b/SocketHttpListener/Net/EndPointManager.cs new file mode 100644 index 000000000..6a00ed360 --- /dev/null +++ b/SocketHttpListener/Net/EndPointManager.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Threading.Tasks; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + sealed class EndPointManager + { + // Dictionary> + static Dictionary> ip_to_endpoints = new Dictionary>(); + + private EndPointManager() + { + } + + public static void AddListener(ILogger logger, HttpListener listener) + { + List added = new List(); + try + { + lock (ip_to_endpoints) + { + foreach (string prefix in listener.Prefixes) + { + AddPrefixInternal(logger, prefix, listener); + added.Add(prefix); + } + } + } + catch + { + foreach (string prefix in added) + { + RemovePrefix(logger, prefix, listener); + } + throw; + } + } + + public static void AddPrefix(ILogger logger, string prefix, HttpListener listener) + { + lock (ip_to_endpoints) + { + AddPrefixInternal(logger, prefix, listener); + } + } + + static void AddPrefixInternal(ILogger logger, string p, HttpListener listener) + { + ListenerPrefix lp = new ListenerPrefix(p); + if (lp.Path.IndexOf('%') != -1) + throw new HttpListenerException(400, "Invalid path."); + + if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) // TODO: Code? + throw new HttpListenerException(400, "Invalid path."); + + // listens on all the interfaces if host name cannot be parsed by IPAddress. + EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result; + epl.AddPrefix(lp, listener); + } + + private static IpAddressInfo GetIpAnyAddress(HttpListener listener) + { + return listener.EnableDualMode ? IpAddressInfo.IPv6Any : IpAddressInfo.Any; + } + + static async Task GetEPListener(ILogger logger, string host, int port, HttpListener listener, bool secure) + { + var networkManager = listener.NetworkManager; + + IpAddressInfo addr; + if (host == "*" || host == "+") + addr = GetIpAnyAddress(listener); + else if (networkManager.TryParseIpAddress(host, out addr) == false) + { + try + { + addr = (await networkManager.GetHostAddressesAsync(host).ConfigureAwait(false)).FirstOrDefault() ?? + GetIpAnyAddress(listener); + } + catch + { + addr = GetIpAnyAddress(listener); + } + } + + Dictionary p = null; // Dictionary + if (!ip_to_endpoints.TryGetValue(addr.Address, out p)) + { + p = new Dictionary(); + ip_to_endpoints[addr.Address] = p; + } + + EndPointListener epl = null; + if (p.ContainsKey(port)) + { + epl = (EndPointListener)p[port]; + } + else + { + epl = new EndPointListener(listener, addr, port, secure, listener.Certificate, logger, listener.CryptoProvider, listener.StreamFactory, listener.SocketFactory, listener.MemoryStreamFactory, listener.TextEncoding, listener.FileSystem, listener.EnvironmentInfo); + p[port] = epl; + } + + return epl; + } + + public static void RemoveEndPoint(EndPointListener epl, IpEndPointInfo ep) + { + lock (ip_to_endpoints) + { + // Dictionary p + Dictionary p; + if (ip_to_endpoints.TryGetValue(ep.IpAddress.Address, out p)) + { + p.Remove(ep.Port); + if (p.Count == 0) + { + ip_to_endpoints.Remove(ep.IpAddress.Address); + } + } + epl.Close(); + } + } + + public static void RemoveListener(ILogger logger, HttpListener listener) + { + lock (ip_to_endpoints) + { + foreach (string prefix in listener.Prefixes) + { + RemovePrefixInternal(logger, prefix, listener); + } + } + } + + public static void RemovePrefix(ILogger logger, string prefix, HttpListener listener) + { + lock (ip_to_endpoints) + { + RemovePrefixInternal(logger, prefix, listener); + } + } + + static void RemovePrefixInternal(ILogger logger, string prefix, HttpListener listener) + { + ListenerPrefix lp = new ListenerPrefix(prefix); + if (lp.Path.IndexOf('%') != -1) + return; + + if (lp.Path.IndexOf("//", StringComparison.Ordinal) != -1) + return; + + EndPointListener epl = GetEPListener(logger, lp.Host, lp.Port, listener, lp.Secure).Result; + epl.RemovePrefix(lp, listener); + } + } +} diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs new file mode 100644 index 000000000..848b80f99 --- /dev/null +++ b/SocketHttpListener/Net/HttpConnection.cs @@ -0,0 +1,547 @@ +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + sealed class HttpConnection + { + const int BufferSize = 8192; + IAcceptSocket sock; + Stream stream; + EndPointListener epl; + MemoryStream ms; + byte[] buffer; + HttpListenerContext context; + StringBuilder current_line; + ListenerPrefix prefix; + HttpRequestStream i_stream; + Stream o_stream; + bool chunked; + int reuses; + bool context_bound; + bool secure; + int s_timeout = 300000; // 90k ms for first request, 15k ms from then on + IpEndPointInfo local_ep; + HttpListener last_listener; + int[] client_cert_errors; + ICertificate cert; + Stream ssl_stream; + + private readonly ILogger _logger; + private readonly ICryptoProvider _cryptoProvider; + private readonly IMemoryStreamFactory _memoryStreamFactory; + private readonly ITextEncoding _textEncoding; + private readonly IStreamFactory _streamFactory; + private readonly IFileSystem _fileSystem; + private readonly IEnvironmentInfo _environment; + + private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + { + _logger = logger; + this.sock = sock; + this.epl = epl; + this.secure = secure; + this.cert = cert; + _cryptoProvider = cryptoProvider; + _memoryStreamFactory = memoryStreamFactory; + _textEncoding = textEncoding; + _fileSystem = fileSystem; + _environment = environment; + _streamFactory = streamFactory; + } + + private async Task InitStream() + { + if (secure == false) + { + stream = _streamFactory.CreateNetworkStream(sock, false); + } + else + { + //ssl_stream = epl.Listener.CreateSslStream(new NetworkStream(sock, false), false, (t, c, ch, e) => + //{ + // if (c == null) + // return true; + // var c2 = c as X509Certificate2; + // if (c2 == null) + // c2 = new X509Certificate2(c.GetRawCertData()); + // client_cert = c2; + // client_cert_errors = new int[] { (int)e }; + // return true; + //}); + //stream = ssl_stream.AuthenticatedStream; + + ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(sock, false), false); + await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false); + stream = ssl_stream; + } + Init(); + } + + public static async Task Create(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + { + var connection = new HttpConnection(logger, sock, epl, secure, cert, cryptoProvider, streamFactory, memoryStreamFactory, textEncoding, fileSystem, environment); + + await connection.InitStream().ConfigureAwait(false); + + return connection; + } + + public Stream Stream + { + get + { + return stream; + } + } + + internal int[] ClientCertificateErrors + { + get { return client_cert_errors; } + } + + void Init() + { + if (ssl_stream != null) + { + //ssl_stream.AuthenticateAsServer(client_cert, true, (SslProtocols)ServicePointManager.SecurityProtocol, false); + //_streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert); + } + + context_bound = false; + i_stream = null; + o_stream = null; + prefix = null; + chunked = false; + ms = _memoryStreamFactory.CreateNew(); + position = 0; + input_state = InputState.RequestLine; + line_state = LineState.None; + context = new HttpListenerContext(this, _logger, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem); + } + + public bool IsClosed + { + get { return (sock == null); } + } + + public int Reuses + { + get { return reuses; } + } + + public IpEndPointInfo LocalEndPoint + { + get + { + if (local_ep != null) + return local_ep; + + local_ep = (IpEndPointInfo)sock.LocalEndPoint; + return local_ep; + } + } + + public IpEndPointInfo RemoteEndPoint + { + get { return (IpEndPointInfo)sock.RemoteEndPoint; } + } + + public bool IsSecure + { + get { return secure; } + } + + public ListenerPrefix Prefix + { + get { return prefix; } + set { prefix = value; } + } + + public async Task BeginReadRequest() + { + if (buffer == null) + buffer = new byte[BufferSize]; + + try + { + //if (reuses == 1) + // s_timeout = 15000; + var nRead = await stream.ReadAsync(buffer, 0, BufferSize).ConfigureAwait(false); + + OnReadInternal(nRead); + } + catch (Exception ex) + { + OnReadInternalException(ms, ex); + } + } + + public HttpRequestStream GetRequestStream(bool chunked, long contentlength) + { + if (i_stream == null) + { + byte[] buffer; + _memoryStreamFactory.TryGetBuffer(ms, out buffer); + + int length = (int)ms.Length; + ms = null; + if (chunked) + { + this.chunked = true; + //context.Response.SendChunked = true; + i_stream = new ChunkedInputStream(context, stream, buffer, position, length - position); + } + else + { + i_stream = new HttpRequestStream(stream, buffer, position, length - position, contentlength); + } + } + return i_stream; + } + + public Stream GetResponseStream(bool isExpect100Continue = false) + { + // TODO: can we get this stream before reading the input? + if (o_stream == null) + { + //context.Response.DetermineIfChunked(); + + var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure; + + o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment); + } + return o_stream; + } + + void OnReadInternal(int nread) + { + ms.Write(buffer, 0, nread); + if (ms.Length > 32768) + { + SendError("Bad request", 400); + Close(true); + return; + } + + if (nread == 0) + { + //if (ms.Length > 0) + // SendError (); // Why bother? + CloseSocket(); + Unbind(); + return; + } + + if (ProcessInput(ms)) + { + if (!context.HaveError) + context.Request.FinishInitialization(); + + if (context.HaveError) + { + SendError(); + Close(true); + return; + } + + if (!epl.BindContext(context)) + { + SendError("Invalid host", 400); + Close(true); + return; + } + HttpListener listener = epl.Listener; + if (last_listener != listener) + { + RemoveConnection(); + listener.AddConnection(this); + last_listener = listener; + } + + context_bound = true; + listener.RegisterContext(context); + return; + } + + BeginReadRequest(); + } + + private void OnReadInternalException(MemoryStream ms, Exception ex) + { + //_logger.ErrorException("Error in HttpConnection.OnReadInternal", ex); + + if (ms != null && ms.Length > 0) + SendError(); + if (sock != null) + { + CloseSocket(); + Unbind(); + } + } + + void RemoveConnection() + { + if (last_listener == null) + epl.RemoveConnection(this); + else + last_listener.RemoveConnection(this); + } + + enum InputState + { + RequestLine, + Headers + } + + enum LineState + { + None, + CR, + LF + } + + InputState input_state = InputState.RequestLine; + LineState line_state = LineState.None; + int position; + + // true -> done processing + // false -> need more input + bool ProcessInput(MemoryStream ms) + { + byte[] buffer; + _memoryStreamFactory.TryGetBuffer(ms, out buffer); + + int len = (int)ms.Length; + int used = 0; + string line; + + while (true) + { + if (context.HaveError) + return true; + + if (position >= len) + break; + + try + { + line = ReadLine(buffer, position, len - position, ref used); + position += used; + } + catch + { + context.ErrorMessage = "Bad request"; + context.ErrorStatus = 400; + return true; + } + + if (line == null) + break; + + if (line == "") + { + if (input_state == InputState.RequestLine) + continue; + current_line = null; + ms = null; + return true; + } + + if (input_state == InputState.RequestLine) + { + context.Request.SetRequestLine(line); + input_state = InputState.Headers; + } + else + { + try + { + context.Request.AddHeader(line); + } + catch (Exception e) + { + context.ErrorMessage = e.Message; + context.ErrorStatus = 400; + return true; + } + } + } + + if (used == len) + { + ms.SetLength(0); + position = 0; + } + return false; + } + + string ReadLine(byte[] buffer, int offset, int len, ref int used) + { + if (current_line == null) + current_line = new StringBuilder(128); + int last = offset + len; + used = 0; + + for (int i = offset; i < last && line_state != LineState.LF; i++) + { + used++; + byte b = buffer[i]; + if (b == 13) + { + line_state = LineState.CR; + } + else if (b == 10) + { + line_state = LineState.LF; + } + else + { + current_line.Append((char)b); + } + } + + string result = null; + if (line_state == LineState.LF) + { + line_state = LineState.None; + result = current_line.ToString(); + current_line.Length = 0; + } + + return result; + } + + public void SendError(string msg, int status) + { + try + { + HttpListenerResponse response = context.Response; + response.StatusCode = status; + response.ContentType = "text/html"; + string description = HttpListenerResponse.GetStatusDescription(status); + string str; + if (msg != null) + str = String.Format("

{0} ({1})

", description, msg); + else + str = String.Format("

{0}

", description); + + byte[] error = context.Response.ContentEncoding.GetBytes(str); + response.ContentLength64 = error.Length; + response.OutputStream.Write(error, 0, (int)error.Length); + response.Close(); + } + catch + { + // response was already closed + } + } + + public void SendError() + { + SendError(context.ErrorMessage, context.ErrorStatus); + } + + void Unbind() + { + if (context_bound) + { + epl.UnbindContext(context); + context_bound = false; + } + } + + public void Close() + { + Close(false); + } + + private void CloseSocket() + { + if (sock == null) + return; + + try + { + sock.Close(); + } + catch + { + } + finally + { + sock = null; + } + RemoveConnection(); + } + + internal void Close(bool force_close) + { + if (sock != null) + { + if (!context.Request.IsWebSocketRequest || force_close) + { + Stream st = GetResponseStream(); + if (st != null) + { + st.Dispose(); + } + + o_stream = null; + } + } + + if (sock != null) + { + force_close |= !context.Request.KeepAlive; + if (!force_close) + force_close = (string.Equals(context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase)); + /* + if (!force_close) { +// bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 || +// status_code == 413 || status_code == 414 || status_code == 500 || +// status_code == 503); + force_close |= (context.Request.ProtocolVersion <= HttpVersion.Version10); + } + */ + + if (!force_close && context.Request.FlushInput()) + { + reuses++; + Unbind(); + Init(); + BeginReadRequest(); + return; + } + + IAcceptSocket s = sock; + sock = null; + try + { + if (s != null) + s.Shutdown(true); + } + catch + { + } + finally + { + if (s != null) + s.Close(); + } + Unbind(); + RemoveConnection(); + return; + } + } + } +} \ No newline at end of file diff --git a/SocketHttpListener/Net/HttpListener.cs b/SocketHttpListener/Net/HttpListener.cs new file mode 100644 index 000000000..b3e01425c --- /dev/null +++ b/SocketHttpListener/Net/HttpListener.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + public sealed class HttpListener : IDisposable + { + internal ICryptoProvider CryptoProvider { get; private set; } + internal IStreamFactory StreamFactory { get; private set; } + internal ISocketFactory SocketFactory { get; private set; } + internal IFileSystem FileSystem { get; private set; } + internal ITextEncoding TextEncoding { get; private set; } + internal IMemoryStreamFactory MemoryStreamFactory { get; private set; } + internal INetworkManager NetworkManager { get; private set; } + internal IEnvironmentInfo EnvironmentInfo { get; private set; } + + public bool EnableDualMode { get; set; } + + AuthenticationSchemes auth_schemes; + HttpListenerPrefixCollection prefixes; + AuthenticationSchemeSelector auth_selector; + string realm; + bool unsafe_ntlm_auth; + bool listening; + bool disposed; + + Dictionary registry; // Dictionary + Dictionary connections; + private ILogger _logger; + private ICertificate _certificate; + + public Action OnContext { get; set; } + + public HttpListener(ILogger logger, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + { + _logger = logger; + CryptoProvider = cryptoProvider; + StreamFactory = streamFactory; + SocketFactory = socketFactory; + NetworkManager = networkManager; + TextEncoding = textEncoding; + MemoryStreamFactory = memoryStreamFactory; + FileSystem = fileSystem; + EnvironmentInfo = environmentInfo; + prefixes = new HttpListenerPrefixCollection(logger, this); + registry = new Dictionary(); + connections = new Dictionary(); + auth_schemes = AuthenticationSchemes.Anonymous; + } + + public HttpListener(ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + :this(new NullLogger(), certificate, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) + { + } + + public HttpListener(ILogger logger, ICertificate certificate, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, ISocketFactory socketFactory, INetworkManager networkManager, ITextEncoding textEncoding, IMemoryStreamFactory memoryStreamFactory, IFileSystem fileSystem, IEnvironmentInfo environmentInfo) + : this(logger, cryptoProvider, streamFactory, socketFactory, networkManager, textEncoding, memoryStreamFactory, fileSystem, environmentInfo) + { + _certificate = certificate; + } + + public void LoadCert(ICertificate cert) + { + _certificate = cert; + } + + // TODO: Digest, NTLM and Negotiate require ControlPrincipal + public AuthenticationSchemes AuthenticationSchemes + { + get { return auth_schemes; } + set + { + CheckDisposed(); + auth_schemes = value; + } + } + + public AuthenticationSchemeSelector AuthenticationSchemeSelectorDelegate + { + get { return auth_selector; } + set + { + CheckDisposed(); + auth_selector = value; + } + } + + public bool IsListening + { + get { return listening; } + } + + public static bool IsSupported + { + get { return true; } + } + + public HttpListenerPrefixCollection Prefixes + { + get + { + CheckDisposed(); + return prefixes; + } + } + + // TODO: use this + public string Realm + { + get { return realm; } + set + { + CheckDisposed(); + realm = value; + } + } + + public bool UnsafeConnectionNtlmAuthentication + { + get { return unsafe_ntlm_auth; } + set + { + CheckDisposed(); + unsafe_ntlm_auth = value; + } + } + + //internal IMonoSslStream CreateSslStream(Stream innerStream, bool ownsStream, MSI.MonoRemoteCertificateValidationCallback callback) + //{ + // lock (registry) + // { + // if (tlsProvider == null) + // tlsProvider = MonoTlsProviderFactory.GetProviderInternal(); + // if (tlsSettings == null) + // tlsSettings = MSI.MonoTlsSettings.CopyDefaultSettings(); + // if (tlsSettings.RemoteCertificateValidationCallback == null) + // tlsSettings.RemoteCertificateValidationCallback = callback; + // return tlsProvider.CreateSslStream(innerStream, ownsStream, tlsSettings); + // } + //} + + internal ICertificate Certificate + { + get { return _certificate; } + } + + public void Abort() + { + if (disposed) + return; + + if (!listening) + { + return; + } + + Close(true); + } + + public void Close() + { + if (disposed) + return; + + if (!listening) + { + disposed = true; + return; + } + + Close(true); + disposed = true; + } + + void Close(bool force) + { + CheckDisposed(); + EndPointManager.RemoveListener(_logger, this); + Cleanup(force); + } + + void Cleanup(bool close_existing) + { + lock (registry) + { + if (close_existing) + { + // Need to copy this since closing will call UnregisterContext + ICollection keys = registry.Keys; + var all = new HttpListenerContext[keys.Count]; + keys.CopyTo(all, 0); + registry.Clear(); + for (int i = all.Length - 1; i >= 0; i--) + all[i].Connection.Close(true); + } + + lock (connections) + { + ICollection keys = connections.Keys; + var conns = new HttpConnection[keys.Count]; + keys.CopyTo(conns, 0); + connections.Clear(); + for (int i = conns.Length - 1; i >= 0; i--) + conns[i].Close(true); + } + } + } + + internal AuthenticationSchemes SelectAuthenticationScheme(HttpListenerContext context) + { + if (AuthenticationSchemeSelectorDelegate != null) + return AuthenticationSchemeSelectorDelegate(context.Request); + else + return auth_schemes; + } + + public void Start() + { + CheckDisposed(); + if (listening) + return; + + EndPointManager.AddListener(_logger, this); + listening = true; + } + + public void Stop() + { + CheckDisposed(); + listening = false; + Close(false); + } + + void IDisposable.Dispose() + { + if (disposed) + return; + + Close(true); //TODO: Should we force here or not? + disposed = true; + } + + internal void CheckDisposed() + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + } + + internal void RegisterContext(HttpListenerContext context) + { + if (OnContext != null && IsListening) + { + OnContext(context); + } + + lock (registry) + registry[context] = context; + } + + internal void UnregisterContext(HttpListenerContext context) + { + lock (registry) + registry.Remove(context); + } + + internal void AddConnection(HttpConnection cnc) + { + lock (connections) + { + connections[cnc] = cnc; + } + } + + internal void RemoveConnection(HttpConnection cnc) + { + lock (connections) + { + connections.Remove(cnc); + } + } + } +} diff --git a/SocketHttpListener/Net/HttpListenerBasicIdentity.cs b/SocketHttpListener/Net/HttpListenerBasicIdentity.cs new file mode 100644 index 000000000..faa26693d --- /dev/null +++ b/SocketHttpListener/Net/HttpListenerBasicIdentity.cs @@ -0,0 +1,70 @@ +using System.Security.Principal; + +namespace SocketHttpListener.Net +{ + public class HttpListenerBasicIdentity : GenericIdentity + { + string password; + + public HttpListenerBasicIdentity(string username, string password) + : base(username, "Basic") + { + this.password = password; + } + + public virtual string Password + { + get { return password; } + } + } + + public class GenericIdentity : IIdentity + { + private string m_name; + private string m_type; + + public GenericIdentity(string name) + { + if (name == null) + throw new System.ArgumentNullException("name"); + + m_name = name; + m_type = ""; + } + + public GenericIdentity(string name, string type) + { + if (name == null) + throw new System.ArgumentNullException("name"); + if (type == null) + throw new System.ArgumentNullException("type"); + + m_name = name; + m_type = type; + } + + public virtual string Name + { + get + { + return m_name; + } + } + + public virtual string AuthenticationType + { + get + { + return m_type; + } + } + + public virtual bool IsAuthenticated + { + get + { + return !m_name.Equals(""); + } + } + } +} diff --git a/SocketHttpListener/Net/HttpListenerContext.cs b/SocketHttpListener/Net/HttpListenerContext.cs new file mode 100644 index 000000000..58d769f22 --- /dev/null +++ b/SocketHttpListener/Net/HttpListenerContext.cs @@ -0,0 +1,198 @@ +using System; +using System.Net; +using System.Security.Principal; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Text; +using SocketHttpListener.Net.WebSockets; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + public sealed class HttpListenerContext + { + HttpListenerRequest request; + HttpListenerResponse response; + IPrincipal user; + HttpConnection cnc; + string error; + int err_status = 400; + private readonly ICryptoProvider _cryptoProvider; + private readonly IMemoryStreamFactory _memoryStreamFactory; + private readonly ITextEncoding _textEncoding; + + internal HttpListenerContext(HttpConnection cnc, ILogger logger, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem) + { + this.cnc = cnc; + _cryptoProvider = cryptoProvider; + _memoryStreamFactory = memoryStreamFactory; + _textEncoding = textEncoding; + request = new HttpListenerRequest(this, _textEncoding); + response = new HttpListenerResponse(this, logger, _textEncoding, fileSystem); + } + + internal int ErrorStatus + { + get { return err_status; } + set { err_status = value; } + } + + internal string ErrorMessage + { + get { return error; } + set { error = value; } + } + + internal bool HaveError + { + get { return (error != null); } + } + + internal HttpConnection Connection + { + get { return cnc; } + } + + public HttpListenerRequest Request + { + get { return request; } + } + + public HttpListenerResponse Response + { + get { return response; } + } + + public IPrincipal User + { + get { return user; } + } + + internal void ParseAuthentication(AuthenticationSchemes expectedSchemes) + { + if (expectedSchemes == AuthenticationSchemes.Anonymous) + return; + + // TODO: Handle NTLM/Digest modes + string header = request.Headers["Authorization"]; + if (header == null || header.Length < 2) + return; + + string[] authenticationData = header.Split(new char[] { ' ' }, 2); + if (string.Equals(authenticationData[0], "basic", StringComparison.OrdinalIgnoreCase)) + { + user = ParseBasicAuthentication(authenticationData[1]); + } + // TODO: throw if malformed -> 400 bad request + } + + internal IPrincipal ParseBasicAuthentication(string authData) + { + try + { + // Basic AUTH Data is a formatted Base64 String + //string domain = null; + string user = null; + string password = null; + int pos = -1; + var authDataBytes = Convert.FromBase64String(authData); + string authString = _textEncoding.GetDefaultEncoding().GetString(authDataBytes, 0, authDataBytes.Length); + + // The format is DOMAIN\username:password + // Domain is optional + + pos = authString.IndexOf(':'); + + // parse the password off the end + password = authString.Substring(pos + 1); + + // discard the password + authString = authString.Substring(0, pos); + + // check if there is a domain + pos = authString.IndexOf('\\'); + + if (pos > 0) + { + //domain = authString.Substring (0, pos); + user = authString.Substring(pos); + } + else + { + user = authString; + } + + HttpListenerBasicIdentity identity = new HttpListenerBasicIdentity(user, password); + // TODO: What are the roles MS sets + return new GenericPrincipal(identity, new string[0]); + } + catch (Exception) + { + // Invalid auth data is swallowed silently + return null; + } + } + + public HttpListenerWebSocketContext AcceptWebSocket(string protocol) + { + if (protocol != null) + { + if (protocol.Length == 0) + throw new ArgumentException("An empty string.", "protocol"); + + if (!protocol.IsToken()) + throw new ArgumentException("Contains an invalid character.", "protocol"); + } + + return new HttpListenerWebSocketContext(this, protocol, _cryptoProvider, _memoryStreamFactory); + } + } + + public class GenericPrincipal : IPrincipal + { + private IIdentity m_identity; + private string[] m_roles; + + public GenericPrincipal(IIdentity identity, string[] roles) + { + if (identity == null) + throw new ArgumentNullException("identity"); + + m_identity = identity; + if (roles != null) + { + m_roles = new string[roles.Length]; + for (int i = 0; i < roles.Length; ++i) + { + m_roles[i] = roles[i]; + } + } + else + { + m_roles = null; + } + } + + public virtual IIdentity Identity + { + get + { + return m_identity; + } + } + + public virtual bool IsInRole(string role) + { + if (role == null || m_roles == null) + return false; + + for (int i = 0; i < m_roles.Length; ++i) + { + if (m_roles[i] != null && String.Compare(m_roles[i], role, StringComparison.OrdinalIgnoreCase) == 0) + return true; + } + return false; + } + } +} diff --git a/SocketHttpListener/Net/HttpListenerPrefixCollection.cs b/SocketHttpListener/Net/HttpListenerPrefixCollection.cs new file mode 100644 index 000000000..0b05539ee --- /dev/null +++ b/SocketHttpListener/Net/HttpListenerPrefixCollection.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using MediaBrowser.Model.Logging; + +namespace SocketHttpListener.Net +{ + public class HttpListenerPrefixCollection : ICollection, IEnumerable, IEnumerable + { + List prefixes = new List(); + HttpListener listener; + + private ILogger _logger; + + internal HttpListenerPrefixCollection(ILogger logger, HttpListener listener) + { + _logger = logger; + this.listener = listener; + } + + public int Count + { + get { return prefixes.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public void Add(string uriPrefix) + { + listener.CheckDisposed(); + ListenerPrefix.CheckUri(uriPrefix); + if (prefixes.Contains(uriPrefix)) + return; + + prefixes.Add(uriPrefix); + if (listener.IsListening) + EndPointManager.AddPrefix(_logger, uriPrefix, listener); + } + + public void Clear() + { + listener.CheckDisposed(); + prefixes.Clear(); + if (listener.IsListening) + EndPointManager.RemoveListener(_logger, listener); + } + + public bool Contains(string uriPrefix) + { + listener.CheckDisposed(); + return prefixes.Contains(uriPrefix); + } + + public void CopyTo(string[] array, int offset) + { + listener.CheckDisposed(); + prefixes.CopyTo(array, offset); + } + + public void CopyTo(Array array, int offset) + { + listener.CheckDisposed(); + ((ICollection)prefixes).CopyTo(array, offset); + } + + public IEnumerator GetEnumerator() + { + return prefixes.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return prefixes.GetEnumerator(); + } + + public bool Remove(string uriPrefix) + { + listener.CheckDisposed(); + if (uriPrefix == null) + throw new ArgumentNullException("uriPrefix"); + + bool result = prefixes.Remove(uriPrefix); + if (result && listener.IsListening) + EndPointManager.RemovePrefix(_logger, uriPrefix, listener); + + return result; + } + } +} diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs new file mode 100644 index 000000000..cfbd49203 --- /dev/null +++ b/SocketHttpListener/Net/HttpListenerRequest.cs @@ -0,0 +1,654 @@ +using System; +using System.Collections.Specialized; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Services; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + public sealed class HttpListenerRequest + { + string[] accept_types; + Encoding content_encoding; + long content_length; + bool cl_set; + CookieCollection cookies; + WebHeaderCollection headers; + string method; + Stream input_stream; + Version version; + QueryParamCollection query_string; // check if null is ok, check if read-only, check case-sensitiveness + string raw_url; + Uri url; + Uri referrer; + string[] user_languages; + HttpListenerContext context; + bool is_chunked; + bool ka_set; + bool keep_alive; + + private readonly ITextEncoding _textEncoding; + + internal HttpListenerRequest(HttpListenerContext context, ITextEncoding textEncoding) + { + this.context = context; + _textEncoding = textEncoding; + headers = new WebHeaderCollection(); + version = HttpVersion.Version10; + } + + static char[] separators = new char[] { ' ' }; + + internal void SetRequestLine(string req) + { + string[] parts = req.Split(separators, 3); + if (parts.Length != 3) + { + context.ErrorMessage = "Invalid request line (parts)."; + return; + } + + method = parts[0]; + foreach (char c in method) + { + int ic = (int)c; + + if ((ic >= 'A' && ic <= 'Z') || + (ic > 32 && c < 127 && c != '(' && c != ')' && c != '<' && + c != '<' && c != '>' && c != '@' && c != ',' && c != ';' && + c != ':' && c != '\\' && c != '"' && c != '/' && c != '[' && + c != ']' && c != '?' && c != '=' && c != '{' && c != '}')) + continue; + + context.ErrorMessage = "(Invalid verb)"; + return; + } + + raw_url = parts[1]; + if (parts[2].Length != 8 || !parts[2].StartsWith("HTTP/")) + { + context.ErrorMessage = "Invalid request line (version)."; + return; + } + + try + { + version = new Version(parts[2].Substring(5)); + if (version.Major < 1) + throw new Exception(); + } + catch + { + context.ErrorMessage = "Invalid request line (version)."; + return; + } + } + + void CreateQueryString(string query) + { + if (query == null || query.Length == 0) + { + query_string = new QueryParamCollection(); + return; + } + + query_string = new QueryParamCollection(); + if (query[0] == '?') + query = query.Substring(1); + string[] components = query.Split('&'); + foreach (string kv in components) + { + int pos = kv.IndexOf('='); + if (pos == -1) + { + query_string.Add(null, WebUtility.UrlDecode(kv)); + } + else + { + string key = WebUtility.UrlDecode(kv.Substring(0, pos)); + string val = WebUtility.UrlDecode(kv.Substring(pos + 1)); + + query_string.Add(key, val); + } + } + } + + internal void FinishInitialization() + { + string host = UserHostName; + if (version > HttpVersion.Version10 && (host == null || host.Length == 0)) + { + context.ErrorMessage = "Invalid host name"; + return; + } + + string path; + Uri raw_uri = null; + if (MaybeUri(raw_url.ToLowerInvariant()) && Uri.TryCreate(raw_url, UriKind.Absolute, out raw_uri)) + path = raw_uri.PathAndQuery; + else + path = raw_url; + + if ((host == null || host.Length == 0)) + host = UserHostAddress; + + if (raw_uri != null) + host = raw_uri.Host; + + int colon = host.LastIndexOf(':'); + if (colon >= 0) + host = host.Substring(0, colon); + + string base_uri = String.Format("{0}://{1}:{2}", + (IsSecureConnection) ? (IsWebSocketRequest ? "wss" : "https") : (IsWebSocketRequest ? "ws" : "http"), + host, LocalEndPoint.Port); + + if (!Uri.TryCreate(base_uri + path, UriKind.Absolute, out url)) + { + context.ErrorMessage = WebUtility.HtmlEncode("Invalid url: " + base_uri + path); + return; return; + } + + CreateQueryString(url.Query); + + if (version >= HttpVersion.Version11) + { + string t_encoding = Headers["Transfer-Encoding"]; + is_chunked = (t_encoding != null && String.Compare(t_encoding, "chunked", StringComparison.OrdinalIgnoreCase) == 0); + // 'identity' is not valid! + if (t_encoding != null && !is_chunked) + { + context.Connection.SendError(null, 501); + return; + } + } + + if (!is_chunked && !cl_set) + { + if (String.Compare(method, "POST", StringComparison.OrdinalIgnoreCase) == 0 || + String.Compare(method, "PUT", StringComparison.OrdinalIgnoreCase) == 0) + { + context.Connection.SendError(null, 411); + return; + } + } + + if (String.Compare(Headers["Expect"], "100-continue", StringComparison.OrdinalIgnoreCase) == 0) + { + var output = (ResponseStream)context.Connection.GetResponseStream(true); + + var _100continue = _textEncoding.GetASCIIEncoding().GetBytes("HTTP/1.1 100 Continue\r\n\r\n"); + + output.InternalWrite(_100continue, 0, _100continue.Length); + } + } + + static bool MaybeUri(string s) + { + int p = s.IndexOf(':'); + if (p == -1) + return false; + + if (p >= 10) + return false; + + return IsPredefinedScheme(s.Substring(0, p)); + } + + // + // Using a simple block of if's is twice as slow as the compiler generated + // switch statement. But using this tuned code is faster than the + // compiler generated code, with a million loops on x86-64: + // + // With "http": .10 vs .51 (first check) + // with "https": .16 vs .51 (second check) + // with "foo": .22 vs .31 (never found) + // with "mailto": .12 vs .51 (last check) + // + // + static bool IsPredefinedScheme(string scheme) + { + if (scheme == null || scheme.Length < 3) + return false; + + char c = scheme[0]; + if (c == 'h') + return (scheme == "http" || scheme == "https"); + if (c == 'f') + return (scheme == "file" || scheme == "ftp"); + + if (c == 'n') + { + c = scheme[1]; + if (c == 'e') + return (scheme == "news" || scheme == "net.pipe" || scheme == "net.tcp"); + if (scheme == "nntp") + return true; + return false; + } + if ((c == 'g' && scheme == "gopher") || (c == 'm' && scheme == "mailto")) + return true; + + return false; + } + + internal static string Unquote(String str) + { + int start = str.IndexOf('\"'); + int end = str.LastIndexOf('\"'); + if (start >= 0 && end >= 0) + str = str.Substring(start + 1, end - 1); + return str.Trim(); + } + + internal void AddHeader(string header) + { + int colon = header.IndexOf(':'); + if (colon == -1 || colon == 0) + { + context.ErrorMessage = "Bad Request"; + context.ErrorStatus = 400; + return; + } + + string name = header.Substring(0, colon).Trim(); + string val = header.Substring(colon + 1).Trim(); + string lower = name.ToLowerInvariant(); + headers.SetInternal(name, val); + switch (lower) + { + case "accept-language": + user_languages = val.Split(','); // yes, only split with a ',' + break; + case "accept": + accept_types = val.Split(','); // yes, only split with a ',' + break; + case "content-length": + try + { + //TODO: max. content_length? + content_length = Int64.Parse(val.Trim()); + if (content_length < 0) + context.ErrorMessage = "Invalid Content-Length."; + cl_set = true; + } + catch + { + context.ErrorMessage = "Invalid Content-Length."; + } + + break; + case "content-type": + { + var contents = val.Split(';'); + foreach (var content in contents) + { + var tmp = content.Trim(); + if (tmp.StartsWith("charset")) + { + var charset = tmp.GetValue("="); + if (charset != null && charset.Length > 0) + { + try + { + + // Support upnp/dlna devices - CONTENT-TYPE: text/xml ; charset="utf-8"\r\n + charset = charset.Trim('"'); + var index = charset.IndexOf('"'); + if (index != -1) charset = charset.Substring(0, index); + + content_encoding = Encoding.GetEncoding(charset); + } + catch + { + context.ErrorMessage = "Invalid Content-Type header: " + charset; + } + } + + break; + } + } + } + break; + case "referer": + try + { + referrer = new Uri(val); + } + catch + { + referrer = new Uri("http://someone.is.screwing.with.the.headers.com/"); + } + break; + case "cookie": + if (cookies == null) + cookies = new CookieCollection(); + + string[] cookieStrings = val.Split(new char[] { ',', ';' }); + Cookie current = null; + int version = 0; + foreach (string cookieString in cookieStrings) + { + string str = cookieString.Trim(); + if (str.Length == 0) + continue; + if (str.StartsWith("$Version")) + { + version = Int32.Parse(Unquote(str.Substring(str.IndexOf('=') + 1))); + } + else if (str.StartsWith("$Path")) + { + if (current != null) + current.Path = str.Substring(str.IndexOf('=') + 1).Trim(); + } + else if (str.StartsWith("$Domain")) + { + if (current != null) + current.Domain = str.Substring(str.IndexOf('=') + 1).Trim(); + } + else if (str.StartsWith("$Port")) + { + if (current != null) + current.Port = str.Substring(str.IndexOf('=') + 1).Trim(); + } + else + { + if (current != null) + { + cookies.Add(current); + } + current = new Cookie(); + int idx = str.IndexOf('='); + if (idx > 0) + { + current.Name = str.Substring(0, idx).Trim(); + current.Value = str.Substring(idx + 1).Trim(); + } + else + { + current.Name = str.Trim(); + current.Value = String.Empty; + } + current.Version = version; + } + } + if (current != null) + { + cookies.Add(current); + } + break; + } + } + + // returns true is the stream could be reused. + internal bool FlushInput() + { + if (!HasEntityBody) + return true; + + int length = 2048; + if (content_length > 0) + length = (int)Math.Min(content_length, (long)length); + + byte[] bytes = new byte[length]; + while (true) + { + // TODO: test if MS has a timeout when doing this + try + { + var task = InputStream.ReadAsync(bytes, 0, length); + var result = Task.WaitAll(new [] { task }, 1000); + if (!result) + { + return false; + } + if (task.Result <= 0) + { + return true; + } + } + catch (ObjectDisposedException e) + { + input_stream = null; + return true; + } + catch + { + return false; + } + } + } + + public string[] AcceptTypes + { + get { return accept_types; } + } + + public int ClientCertificateError + { + get + { + HttpConnection cnc = context.Connection; + //if (cnc.ClientCertificate == null) + // throw new InvalidOperationException("No client certificate"); + //int[] errors = cnc.ClientCertificateErrors; + //if (errors != null && errors.Length > 0) + // return errors[0]; + return 0; + } + } + + public Encoding ContentEncoding + { + get + { + if (content_encoding == null) + content_encoding = _textEncoding.GetDefaultEncoding(); + return content_encoding; + } + } + + public long ContentLength64 + { + get { return is_chunked ? -1 : content_length; } + } + + public string ContentType + { + get { return headers["content-type"]; } + } + + public CookieCollection Cookies + { + get + { + // TODO: check if the collection is read-only + if (cookies == null) + cookies = new CookieCollection(); + return cookies; + } + } + + public bool HasEntityBody + { + get { return (content_length > 0 || is_chunked); } + } + + public QueryParamCollection Headers + { + get { return headers; } + } + + public string HttpMethod + { + get { return method; } + } + + public Stream InputStream + { + get + { + if (input_stream == null) + { + if (is_chunked || content_length > 0) + input_stream = context.Connection.GetRequestStream(is_chunked, content_length); + else + input_stream = Stream.Null; + } + + return input_stream; + } + } + + public bool IsAuthenticated + { + get { return false; } + } + + public bool IsLocal + { + get { return RemoteEndPoint.IpAddress.Equals(IpAddressInfo.Loopback) || RemoteEndPoint.IpAddress.Equals(IpAddressInfo.IPv6Loopback) || LocalEndPoint.IpAddress.Equals(RemoteEndPoint.IpAddress); } + } + + public bool IsSecureConnection + { + get { return context.Connection.IsSecure; } + } + + public bool KeepAlive + { + get + { + if (ka_set) + return keep_alive; + + ka_set = true; + // 1. Connection header + // 2. Protocol (1.1 == keep-alive by default) + // 3. Keep-Alive header + string cnc = headers["Connection"]; + if (!String.IsNullOrEmpty(cnc)) + { + keep_alive = (0 == String.Compare(cnc, "keep-alive", StringComparison.OrdinalIgnoreCase)); + } + else if (version == HttpVersion.Version11) + { + keep_alive = true; + } + else + { + cnc = headers["keep-alive"]; + if (!String.IsNullOrEmpty(cnc)) + keep_alive = (0 != String.Compare(cnc, "closed", StringComparison.OrdinalIgnoreCase)); + } + return keep_alive; + } + } + + public IpEndPointInfo LocalEndPoint + { + get { return context.Connection.LocalEndPoint; } + } + + public Version ProtocolVersion + { + get { return version; } + } + + public QueryParamCollection QueryString + { + get { return query_string; } + } + + public string RawUrl + { + get { return raw_url; } + } + + public IpEndPointInfo RemoteEndPoint + { + get { return context.Connection.RemoteEndPoint; } + } + + public Guid RequestTraceIdentifier + { + get { return Guid.Empty; } + } + + public Uri Url + { + get { return url; } + } + + public Uri UrlReferrer + { + get { return referrer; } + } + + public string UserAgent + { + get { return headers["user-agent"]; } + } + + public string UserHostAddress + { + get { return LocalEndPoint.ToString(); } + } + + public string UserHostName + { + get { return headers["host"]; } + } + + public string[] UserLanguages + { + get { return user_languages; } + } + + public string ServiceName + { + get + { + return null; + } + } + + private bool _websocketRequestWasSet; + private bool _websocketRequest; + + /// + /// Gets a value indicating whether the request is a WebSocket connection request. + /// + /// + /// true if the request is a WebSocket connection request; otherwise, false. + /// + public bool IsWebSocketRequest + { + get + { + if (!_websocketRequestWasSet) + { + _websocketRequest = method == "GET" && + version > HttpVersion.Version10 && + headers.Contains("Upgrade", "websocket") && + headers.Contains("Connection", "Upgrade"); + + _websocketRequestWasSet = true; + } + + return _websocketRequest; + } + } + + public Task GetClientCertificateAsync() + { + return Task.FromResult(null); + } + } +} diff --git a/SocketHttpListener/Net/HttpListenerResponse.cs b/SocketHttpListener/Net/HttpListenerResponse.cs new file mode 100644 index 000000000..3cb6a0d75 --- /dev/null +++ b/SocketHttpListener/Net/HttpListenerResponse.cs @@ -0,0 +1,525 @@ +using System; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + public sealed class HttpListenerResponse : IDisposable + { + bool disposed; + Encoding content_encoding; + long content_length; + bool cl_set; + string content_type; + CookieCollection cookies; + WebHeaderCollection headers = new WebHeaderCollection(); + bool keep_alive = true; + Stream output_stream; + Version version = HttpVersion.Version11; + string location; + int status_code = 200; + string status_description = "OK"; + bool chunked; + HttpListenerContext context; + + internal bool HeadersSent; + internal object headers_lock = new object(); + + private readonly ILogger _logger; + private readonly ITextEncoding _textEncoding; + private readonly IFileSystem _fileSystem; + + internal HttpListenerResponse(HttpListenerContext context, ILogger logger, ITextEncoding textEncoding, IFileSystem fileSystem) + { + this.context = context; + _logger = logger; + _textEncoding = textEncoding; + _fileSystem = fileSystem; + } + + internal bool CloseConnection + { + get + { + return headers["Connection"] == "close"; + } + } + + public Encoding ContentEncoding + { + get + { + if (content_encoding == null) + content_encoding = _textEncoding.GetDefaultEncoding(); + return content_encoding; + } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + content_encoding = value; + } + } + + public long ContentLength64 + { + get { return content_length; } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + if (HeadersSent) + throw new InvalidOperationException("Cannot be changed after headers are sent."); + + if (value < 0) + throw new ArgumentOutOfRangeException("Must be >= 0", "value"); + + cl_set = true; + content_length = value; + } + } + + public string ContentType + { + get { return content_type; } + set + { + // TODO: is null ok? + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + content_type = value; + } + } + + // RFC 2109, 2965 + the netscape specification at http://wp.netscape.com/newsref/std/cookie_spec.html + public CookieCollection Cookies + { + get + { + if (cookies == null) + cookies = new CookieCollection(); + return cookies; + } + set { cookies = value; } // null allowed? + } + + public WebHeaderCollection Headers + { + get { return headers; } + set + { + /** + * "If you attempt to set a Content-Length, Keep-Alive, Transfer-Encoding, or + * WWW-Authenticate header using the Headers property, an exception will be + * thrown. Use the KeepAlive or ContentLength64 properties to set these headers. + * You cannot set the Transfer-Encoding or WWW-Authenticate headers manually." + */ + // TODO: check if this is marked readonly after headers are sent. + headers = value; + } + } + + public bool KeepAlive + { + get { return keep_alive; } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + keep_alive = value; + } + } + + public Stream OutputStream + { + get + { + if (output_stream == null) + output_stream = context.Connection.GetResponseStream(); + return output_stream; + } + } + + public Version ProtocolVersion + { + get { return version; } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + if (value == null) + throw new ArgumentNullException("value"); + + if (value.Major != 1 || (value.Minor != 0 && value.Minor != 1)) + throw new ArgumentException("Must be 1.0 or 1.1", "value"); + + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + version = value; + } + } + + public string RedirectLocation + { + get { return location; } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + location = value; + } + } + + public bool SendChunked + { + get { return chunked; } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + chunked = value; + } + } + + public int StatusCode + { + get { return status_code; } + set + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + if (value < 100 || value > 999) + throw new ProtocolViolationException("StatusCode must be between 100 and 999."); + status_code = value; + status_description = GetStatusDescription(value); + } + } + + internal static string GetStatusDescription(int code) + { + switch (code) + { + case 100: return "Continue"; + case 101: return "Switching Protocols"; + case 102: return "Processing"; + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 203: return "Non-Authoritative Information"; + case 204: return "No Content"; + case 205: return "Reset Content"; + case 206: return "Partial Content"; + case 207: return "Multi-Status"; + case 300: return "Multiple Choices"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 305: return "Use Proxy"; + case 307: return "Temporary Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 402: return "Payment Required"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 406: return "Not Acceptable"; + case 407: return "Proxy Authentication Required"; + case 408: return "Request Timeout"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 411: return "Length Required"; + case 412: return "Precondition Failed"; + case 413: return "Request Entity Too Large"; + case 414: return "Request-Uri Too Long"; + case 415: return "Unsupported Media Type"; + case 416: return "Requested Range Not Satisfiable"; + case 417: return "Expectation Failed"; + case 422: return "Unprocessable Entity"; + case 423: return "Locked"; + case 424: return "Failed Dependency"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + case 505: return "Http Version Not Supported"; + case 507: return "Insufficient Storage"; + } + return ""; + } + + public string StatusDescription + { + get { return status_description; } + set + { + status_description = value; + } + } + + void IDisposable.Dispose() + { + Close(true); //TODO: Abort or Close? + } + + public void Abort() + { + if (disposed) + return; + + Close(true); + } + + public void AddHeader(string name, string value) + { + if (name == null) + throw new ArgumentNullException("name"); + + if (name == "") + throw new ArgumentException("'name' cannot be empty", "name"); + + //TODO: check for forbidden headers and invalid characters + if (value.Length > 65535) + throw new ArgumentOutOfRangeException("value"); + + headers.Set(name, value); + } + + public void AppendCookie(Cookie cookie) + { + if (cookie == null) + throw new ArgumentNullException("cookie"); + + Cookies.Add(cookie); + } + + public void AppendHeader(string name, string value) + { + if (name == null) + throw new ArgumentNullException("name"); + + if (name == "") + throw new ArgumentException("'name' cannot be empty", "name"); + + if (value.Length > 65535) + throw new ArgumentOutOfRangeException("value"); + + headers.Add(name, value); + } + + private void Close(bool force) + { + if (force) + { + _logger.Debug("HttpListenerResponse force closing HttpConnection"); + } + disposed = true; + context.Connection.Close(force); + } + + public void Close() + { + if (disposed) + return; + + Close(false); + } + + public void Redirect(string url) + { + StatusCode = 302; // Found + location = url; + } + + bool FindCookie(Cookie cookie) + { + string name = cookie.Name; + string domain = cookie.Domain; + string path = cookie.Path; + foreach (Cookie c in cookies) + { + if (name != c.Name) + continue; + if (domain != c.Domain) + continue; + if (path == c.Path) + return true; + } + + return false; + } + + public void DetermineIfChunked() + { + if (chunked) + { + return; + } + + Version v = context.Request.ProtocolVersion; + if (!cl_set && !chunked && v >= HttpVersion.Version11) + chunked = true; + if (!chunked && string.Equals(headers["Transfer-Encoding"], "chunked")) + { + chunked = true; + } + } + + internal void SendHeaders(bool closing, MemoryStream ms) + { + Encoding encoding = content_encoding; + if (encoding == null) + encoding = _textEncoding.GetDefaultEncoding(); + + if (content_type != null) + { + if (content_encoding != null && content_type.IndexOf("charset=", StringComparison.OrdinalIgnoreCase) == -1) + { + string enc_name = content_encoding.WebName; + headers.SetInternal("Content-Type", content_type + "; charset=" + enc_name); + } + else + { + headers.SetInternal("Content-Type", content_type); + } + } + + if (headers["Server"] == null) + headers.SetInternal("Server", "Mono-HTTPAPI/1.0"); + + CultureInfo inv = CultureInfo.InvariantCulture; + if (headers["Date"] == null) + headers.SetInternal("Date", DateTime.UtcNow.ToString("r", inv)); + + if (!chunked) + { + if (!cl_set && closing) + { + cl_set = true; + content_length = 0; + } + + if (cl_set) + headers.SetInternal("Content-Length", content_length.ToString(inv)); + } + + Version v = context.Request.ProtocolVersion; + if (!cl_set && !chunked && v >= HttpVersion.Version11) + chunked = true; + + /* Apache forces closing the connection for these status codes: + * HttpStatusCode.BadRequest 400 + * HttpStatusCode.RequestTimeout 408 + * HttpStatusCode.LengthRequired 411 + * HttpStatusCode.RequestEntityTooLarge 413 + * HttpStatusCode.RequestUriTooLong 414 + * HttpStatusCode.InternalServerError 500 + * HttpStatusCode.ServiceUnavailable 503 + */ + bool conn_close = status_code == 400 || status_code == 408 || status_code == 411 || + status_code == 413 || status_code == 414 || + status_code == 500 || + status_code == 503; + + if (conn_close == false) + conn_close = !context.Request.KeepAlive; + + // They sent both KeepAlive: true and Connection: close!? + if (!keep_alive || conn_close) + { + headers.SetInternal("Connection", "close"); + conn_close = true; + } + + if (chunked) + headers.SetInternal("Transfer-Encoding", "chunked"); + + //int reuses = context.Connection.Reuses; + //if (reuses >= 100) + //{ + // _logger.Debug("HttpListenerResponse - keep alive has exceeded 100 uses and will be closed."); + + // force_close_chunked = true; + // if (!conn_close) + // { + // headers.SetInternal("Connection", "close"); + // conn_close = true; + // } + //} + + if (!conn_close) + { + if (context.Request.ProtocolVersion <= HttpVersion.Version10) + headers.SetInternal("Connection", "keep-alive"); + } + + if (location != null) + headers.SetInternal("Location", location); + + if (cookies != null) + { + foreach (Cookie cookie in cookies) + headers.SetInternal("Set-Cookie", cookie.ToString()); + } + + headers.SetInternal("Status", status_code.ToString(CultureInfo.InvariantCulture)); + + using (StreamWriter writer = new StreamWriter(ms, encoding, 256, true)) + { + writer.Write("HTTP/{0} {1} {2}\r\n", version, status_code, status_description); + string headers_str = headers.ToStringMultiValue(); + writer.Write(headers_str); + writer.Flush(); + } + + int preamble = encoding.GetPreamble().Length; + if (output_stream == null) + output_stream = context.Connection.GetResponseStream(); + + /* Assumes that the ms was at position 0 */ + ms.Position = preamble; + HeadersSent = true; + } + + public void SetCookie(Cookie cookie) + { + if (cookie == null) + throw new ArgumentNullException("cookie"); + + if (cookies != null) + { + if (FindCookie(cookie)) + throw new ArgumentException("The cookie already exists."); + } + else + { + cookies = new CookieCollection(); + } + + cookies.Add(cookie); + } + + public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken); + } + } +} \ No newline at end of file diff --git a/SocketHttpListener/Net/HttpRequestStream.Managed.cs b/SocketHttpListener/Net/HttpRequestStream.Managed.cs new file mode 100644 index 000000000..cb02a4d5a --- /dev/null +++ b/SocketHttpListener/Net/HttpRequestStream.Managed.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.ExceptionServices; +using System.Text; +using System.Threading.Tasks; + +namespace SocketHttpListener.Net +{ + // Licensed to the .NET Foundation under one or more agreements. + // See the LICENSE file in the project root for more information. + // + // System.Net.ResponseStream + // + // Author: + // Gonzalo Paniagua Javier (gonzalo@novell.com) + // + // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + // + // Permission is hereby granted, free of charge, to any person obtaining + // a copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + // + // The above copyright notice and this permission notice shall be + // included in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + // + + internal partial class HttpRequestStream : Stream + { + private byte[] _buffer; + private int _offset; + private int _length; + private long _remainingBody; + protected bool _closed; + private Stream _stream; + + internal HttpRequestStream(Stream stream, byte[] buffer, int offset, int length) + : this(stream, buffer, offset, length, -1) + { + } + + internal HttpRequestStream(Stream stream, byte[] buffer, int offset, int length, long contentlength) + { + _stream = stream; + _buffer = buffer; + _offset = offset; + _length = length; + _remainingBody = contentlength; + } + + // Returns 0 if we can keep reading from the base stream, + // > 0 if we read something from the buffer. + // -1 if we had a content length set and we finished reading that many bytes. + private int FillFromBuffer(byte[] buffer, int offset, int count) + { + if (_remainingBody == 0) + return -1; + + if (_length == 0) + return 0; + + int size = Math.Min(_length, count); + if (_remainingBody > 0) + size = (int)Math.Min(size, _remainingBody); + + if (_offset > _buffer.Length - size) + { + size = Math.Min(size, _buffer.Length - _offset); + } + if (size == 0) + return 0; + + Buffer.BlockCopy(_buffer, _offset, buffer, offset, size); + _offset += size; + _length -= size; + if (_remainingBody > 0) + _remainingBody -= size; + return size; + } + + protected virtual int ReadCore(byte[] buffer, int offset, int size) + { + // Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0 + int nread = FillFromBuffer(buffer, offset, size); + if (nread == -1) + { // No more bytes available (Content-Length) + return 0; + } + else if (nread > 0) + { + return nread; + } + + nread = _stream.Read(buffer, offset, size); + if (nread > 0 && _remainingBody > 0) + _remainingBody -= nread; + return nread; + } + + protected virtual IAsyncResult BeginReadCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state) + { + if (size == 0 || _closed) + { + HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this); + ares._callback = cback; + ares._state = state; + ares.Complete(); + return ares; + } + + int nread = FillFromBuffer(buffer, offset, size); + if (nread > 0 || nread == -1) + { + HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this); + ares._buffer = buffer; + ares._offset = offset; + ares._count = size; + ares._callback = cback; + ares._state = state; + ares._synchRead = Math.Max(0, nread); + ares.Complete(); + return ares; + } + + // Avoid reading past the end of the request to allow + // for HTTP pipelining + if (_remainingBody >= 0 && size > _remainingBody) + { + size = (int)Math.Min(int.MaxValue, _remainingBody); + } + + return _stream.BeginRead(buffer, offset, size, cback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + if (asyncResult == null) + throw new ArgumentNullException(nameof(asyncResult)); + + var r = asyncResult as HttpStreamAsyncResult; + + if (r != null) + { + if (!ReferenceEquals(this, r._parent)) + { + throw new ArgumentException("Invalid async result"); + } + if (r._endCalled) + { + throw new InvalidOperationException("Invalid end call"); + } + r._endCalled = true; + + if (!asyncResult.IsCompleted) + { + asyncResult.AsyncWaitHandle.WaitOne(); + } + + return r._synchRead; + } + + if (_closed) + return 0; + + int nread = 0; + try + { + nread = _stream.EndRead(asyncResult); + } + catch (IOException e) when (e.InnerException is ArgumentException || e.InnerException is InvalidOperationException) + { + throw e.InnerException; + } + + if (_remainingBody > 0 && nread > 0) + { + _remainingBody -= nread; + } + + return nread; + } + } +} diff --git a/SocketHttpListener/Net/HttpRequestStream.cs b/SocketHttpListener/Net/HttpRequestStream.cs new file mode 100644 index 000000000..c54da44a1 --- /dev/null +++ b/SocketHttpListener/Net/HttpRequestStream.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace SocketHttpListener.Net +{ + // Licensed to the .NET Foundation under one or more agreements. + // See the LICENSE file in the project root for more information. + // + // System.Net.ResponseStream + // + // Author: + // Gonzalo Paniagua Javier (gonzalo@novell.com) + // + // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + // + // Permission is hereby granted, free of charge, to any person obtaining + // a copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + // + // The above copyright notice and this permission notice shall be + // included in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + // + + internal partial class HttpRequestStream : Stream + { + public override bool CanSeek => false; + public override bool CanWrite => false; + public override bool CanRead => true; + + public override int Read(byte[] buffer, int offset, int size) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (size < 0 || size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + if (size == 0 || _closed) + { + return 0; + } + + return ReadCore(buffer, offset, size); + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (size < 0 || size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + return BeginReadCore(buffer, offset, size, callback, state); + } + + public override void Flush() { } + public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + public override long Length + { + get + { + throw new NotImplementedException(); + } + } + + public override long Position + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return base.BeginWrite(buffer, offset, count, callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + base.EndWrite(asyncResult); + } + + internal bool Closed => _closed; + + protected override void Dispose(bool disposing) + { + _closed = true; + base.Dispose(disposing); + } + } +} diff --git a/SocketHttpListener/Net/HttpStatusCode.cs b/SocketHttpListener/Net/HttpStatusCode.cs new file mode 100644 index 000000000..93da82ba0 --- /dev/null +++ b/SocketHttpListener/Net/HttpStatusCode.cs @@ -0,0 +1,321 @@ +namespace SocketHttpListener.Net +{ + /// + /// Contains the values of the HTTP status codes. + /// + /// + /// The HttpStatusCode enumeration contains the values of the HTTP status codes defined in + /// RFC 2616 for HTTP 1.1. + /// + public enum HttpStatusCode + { + /// + /// Equivalent to status code 100. + /// Indicates that the client should continue with its request. + /// + Continue = 100, + /// + /// Equivalent to status code 101. + /// Indicates that the server is switching the HTTP version or protocol on the connection. + /// + SwitchingProtocols = 101, + /// + /// Equivalent to status code 200. + /// Indicates that the client's request has succeeded. + /// + OK = 200, + /// + /// Equivalent to status code 201. + /// Indicates that the client's request has been fulfilled and resulted in a new resource being + /// created. + /// + Created = 201, + /// + /// Equivalent to status code 202. + /// Indicates that the client's request has been accepted for processing, but the processing + /// hasn't been completed. + /// + Accepted = 202, + /// + /// Equivalent to status code 203. + /// Indicates that the returned metainformation is from a local or a third-party copy instead of + /// the origin server. + /// + NonAuthoritativeInformation = 203, + /// + /// Equivalent to status code 204. + /// Indicates that the server has fulfilled the client's request but doesn't need to return + /// an entity-body. + /// + NoContent = 204, + /// + /// Equivalent to status code 205. + /// Indicates that the server has fulfilled the client's request, and the user agent should + /// reset the document view which caused the request to be sent. + /// + ResetContent = 205, + /// + /// Equivalent to status code 206. + /// Indicates that the server has fulfilled the partial GET request for the resource. + /// + PartialContent = 206, + /// + /// + /// Equivalent to status code 300. + /// Indicates that the requested resource corresponds to any of multiple representations. + /// + /// + /// MultipleChoices is a synonym for Ambiguous. + /// + /// + MultipleChoices = 300, + /// + /// + /// Equivalent to status code 300. + /// Indicates that the requested resource corresponds to any of multiple representations. + /// + /// + /// Ambiguous is a synonym for MultipleChoices. + /// + /// + Ambiguous = 300, + /// + /// + /// Equivalent to status code 301. + /// Indicates that the requested resource has been assigned a new permanent URI and + /// any future references to this resource should use one of the returned URIs. + /// + /// + /// MovedPermanently is a synonym for Moved. + /// + /// + MovedPermanently = 301, + /// + /// + /// Equivalent to status code 301. + /// Indicates that the requested resource has been assigned a new permanent URI and + /// any future references to this resource should use one of the returned URIs. + /// + /// + /// Moved is a synonym for MovedPermanently. + /// + /// + Moved = 301, + /// + /// + /// Equivalent to status code 302. + /// Indicates that the requested resource is located temporarily under a different URI. + /// + /// + /// Found is a synonym for Redirect. + /// + /// + Found = 302, + /// + /// + /// Equivalent to status code 302. + /// Indicates that the requested resource is located temporarily under a different URI. + /// + /// + /// Redirect is a synonym for Found. + /// + /// + Redirect = 302, + /// + /// + /// Equivalent to status code 303. + /// Indicates that the response to the request can be found under a different URI and + /// should be retrieved using a GET method on that resource. + /// + /// + /// SeeOther is a synonym for RedirectMethod. + /// + /// + SeeOther = 303, + /// + /// + /// Equivalent to status code 303. + /// Indicates that the response to the request can be found under a different URI and + /// should be retrieved using a GET method on that resource. + /// + /// + /// RedirectMethod is a synonym for SeeOther. + /// + /// + RedirectMethod = 303, + /// + /// Equivalent to status code 304. + /// Indicates that the client has performed a conditional GET request and access is allowed, + /// but the document hasn't been modified. + /// + NotModified = 304, + /// + /// Equivalent to status code 305. + /// Indicates that the requested resource must be accessed through the proxy given by + /// the Location field. + /// + UseProxy = 305, + /// + /// Equivalent to status code 306. + /// This status code was used in a previous version of the specification, is no longer used, + /// and is reserved for future use. + /// + Unused = 306, + /// + /// + /// Equivalent to status code 307. + /// Indicates that the requested resource is located temporarily under a different URI. + /// + /// + /// TemporaryRedirect is a synonym for RedirectKeepVerb. + /// + /// + TemporaryRedirect = 307, + /// + /// + /// Equivalent to status code 307. + /// Indicates that the requested resource is located temporarily under a different URI. + /// + /// + /// RedirectKeepVerb is a synonym for TemporaryRedirect. + /// + /// + RedirectKeepVerb = 307, + /// + /// Equivalent to status code 400. + /// Indicates that the client's request couldn't be understood by the server due to + /// malformed syntax. + /// + BadRequest = 400, + /// + /// Equivalent to status code 401. + /// Indicates that the client's request requires user authentication. + /// + Unauthorized = 401, + /// + /// Equivalent to status code 402. + /// This status code is reserved for future use. + /// + PaymentRequired = 402, + /// + /// Equivalent to status code 403. + /// Indicates that the server understood the client's request but is refusing to fulfill it. + /// + Forbidden = 403, + /// + /// Equivalent to status code 404. + /// Indicates that the server hasn't found anything matching the request URI. + /// + NotFound = 404, + /// + /// Equivalent to status code 405. + /// Indicates that the method specified in the request line isn't allowed for the resource + /// identified by the request URI. + /// + MethodNotAllowed = 405, + /// + /// Equivalent to status code 406. + /// Indicates that the server doesn't have the appropriate resource to respond to the Accept + /// headers in the client's request. + /// + NotAcceptable = 406, + /// + /// Equivalent to status code 407. + /// Indicates that the client must first authenticate itself with the proxy. + /// + ProxyAuthenticationRequired = 407, + /// + /// Equivalent to status code 408. + /// Indicates that the client didn't produce a request within the time that the server was + /// prepared to wait. + /// + RequestTimeout = 408, + /// + /// Equivalent to status code 409. + /// Indicates that the client's request couldn't be completed due to a conflict on the server. + /// + Conflict = 409, + /// + /// Equivalent to status code 410. + /// Indicates that the requested resource is no longer available at the server and + /// no forwarding address is known. + /// + Gone = 410, + /// + /// Equivalent to status code 411. + /// Indicates that the server refuses to accept the client's request without a defined + /// Content-Length. + /// + LengthRequired = 411, + /// + /// Equivalent to status code 412. + /// Indicates that the precondition given in one or more of the request headers evaluated to + /// false when it was tested on the server. + /// + PreconditionFailed = 412, + /// + /// Equivalent to status code 413. + /// Indicates that the entity of the client's request is larger than the server is willing or + /// able to process. + /// + RequestEntityTooLarge = 413, + /// + /// Equivalent to status code 414. + /// Indicates that the request URI is longer than the server is willing to interpret. + /// + RequestUriTooLong = 414, + /// + /// Equivalent to status code 415. + /// Indicates that the entity of the client's request is in a format not supported by + /// the requested resource for the requested method. + /// + UnsupportedMediaType = 415, + /// + /// Equivalent to status code 416. + /// Indicates that none of the range specifier values in a Range request header overlap + /// the current extent of the selected resource. + /// + RequestedRangeNotSatisfiable = 416, + /// + /// Equivalent to status code 417. + /// Indicates that the expectation given in an Expect request header couldn't be met by + /// the server. + /// + ExpectationFailed = 417, + /// + /// Equivalent to status code 500. + /// Indicates that the server encountered an unexpected condition which prevented it from + /// fulfilling the client's request. + /// + InternalServerError = 500, + /// + /// Equivalent to status code 501. + /// Indicates that the server doesn't support the functionality required to fulfill the client's + /// request. + /// + NotImplemented = 501, + /// + /// Equivalent to status code 502. + /// Indicates that a gateway or proxy server received an invalid response from the upstream + /// server. + /// + BadGateway = 502, + /// + /// Equivalent to status code 503. + /// Indicates that the server is currently unable to handle the client's request due to + /// a temporary overloading or maintenance of the server. + /// + ServiceUnavailable = 503, + /// + /// Equivalent to status code 504. + /// Indicates that a gateway or proxy server didn't receive a timely response from the upstream + /// server or some other auxiliary server. + /// + GatewayTimeout = 504, + /// + /// Equivalent to status code 505. + /// Indicates that the server doesn't support the HTTP version used in the client's request. + /// + HttpVersionNotSupported = 505, + } +} diff --git a/SocketHttpListener/Net/HttpStreamAsyncResult.cs b/SocketHttpListener/Net/HttpStreamAsyncResult.cs new file mode 100644 index 000000000..e7e516c6b --- /dev/null +++ b/SocketHttpListener/Net/HttpStreamAsyncResult.cs @@ -0,0 +1,85 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace SocketHttpListener.Net +{ + internal class HttpStreamAsyncResult : IAsyncResult + { + private object _locker = new object(); + private ManualResetEvent _handle; + private bool _completed; + + internal readonly object _parent; + internal byte[] _buffer; + internal int _offset; + internal int _count; + internal AsyncCallback _callback; + internal object _state; + internal int _synchRead; + internal Exception _error; + internal bool _endCalled; + + internal HttpStreamAsyncResult(object parent) + { + _parent = parent; + } + + public void Complete(Exception e) + { + _error = e; + Complete(); + } + + public void Complete() + { + lock (_locker) + { + if (_completed) + return; + + _completed = true; + if (_handle != null) + _handle.Set(); + + if (_callback != null) + Task.Run(() => _callback(this)); + } + } + + public object AsyncState + { + get { return _state; } + } + + public WaitHandle AsyncWaitHandle + { + get + { + lock (_locker) + { + if (_handle == null) + _handle = new ManualResetEvent(_completed); + } + + return _handle; + } + } + + public bool CompletedSynchronously + { + get { return (_synchRead == _count); } + } + + public bool IsCompleted + { + get + { + lock (_locker) + { + return _completed; + } + } + } + } +} diff --git a/SocketHttpListener/Net/HttpVersion.cs b/SocketHttpListener/Net/HttpVersion.cs new file mode 100644 index 000000000..c0839b46d --- /dev/null +++ b/SocketHttpListener/Net/HttpVersion.cs @@ -0,0 +1,16 @@ +using System; + +namespace SocketHttpListener.Net +{ + // + // + public class HttpVersion + { + + public static readonly Version Version10 = new Version(1, 0); + public static readonly Version Version11 = new Version(1, 1); + + // pretty useless.. + public HttpVersion() { } + } +} diff --git a/SocketHttpListener/Net/ListenerPrefix.cs b/SocketHttpListener/Net/ListenerPrefix.cs new file mode 100644 index 000000000..2c314da50 --- /dev/null +++ b/SocketHttpListener/Net/ListenerPrefix.cs @@ -0,0 +1,148 @@ +using System; +using System.Net; +using MediaBrowser.Model.Net; + +namespace SocketHttpListener.Net +{ + sealed class ListenerPrefix + { + string original; + string host; + ushort port; + string path; + bool secure; + IpAddressInfo[] addresses; + public HttpListener Listener; + + public ListenerPrefix(string prefix) + { + this.original = prefix; + Parse(prefix); + } + + public override string ToString() + { + return original; + } + + public IpAddressInfo[] Addresses + { + get { return addresses; } + set { addresses = value; } + } + public bool Secure + { + get { return secure; } + } + + public string Host + { + get { return host; } + } + + public int Port + { + get { return (int)port; } + } + + public string Path + { + get { return path; } + } + + // Equals and GetHashCode are required to detect duplicates in HttpListenerPrefixCollection. + public override bool Equals(object o) + { + ListenerPrefix other = o as ListenerPrefix; + if (other == null) + return false; + + return (original == other.original); + } + + public override int GetHashCode() + { + return original.GetHashCode(); + } + + void Parse(string uri) + { + ushort default_port = 80; + if (uri.StartsWith("https://")) + { + default_port = 443; + secure = true; + } + + int length = uri.Length; + int start_host = uri.IndexOf(':') + 3; + if (start_host >= length) + throw new ArgumentException("No host specified."); + + int colon = uri.IndexOf(':', start_host, length - start_host); + int root; + if (colon > 0) + { + host = uri.Substring(start_host, colon - start_host); + root = uri.IndexOf('/', colon, length - colon); + port = (ushort)Int32.Parse(uri.Substring(colon + 1, root - colon - 1)); + path = uri.Substring(root); + } + else + { + root = uri.IndexOf('/', start_host, length - start_host); + host = uri.Substring(start_host, root - start_host); + port = default_port; + path = uri.Substring(root); + } + if (path.Length != 1) + path = path.Substring(0, path.Length - 1); + } + + public static void CheckUri(string uri) + { + if (uri == null) + throw new ArgumentNullException("uriPrefix"); + + if (!uri.StartsWith("http://") && !uri.StartsWith("https://")) + throw new ArgumentException("Only 'http' and 'https' schemes are supported."); + + int length = uri.Length; + int start_host = uri.IndexOf(':') + 3; + if (start_host >= length) + throw new ArgumentException("No host specified."); + + int colon = uri.IndexOf(':', start_host, length - start_host); + if (start_host == colon) + throw new ArgumentException("No host specified."); + + int root; + if (colon > 0) + { + root = uri.IndexOf('/', colon, length - colon); + if (root == -1) + throw new ArgumentException("No path specified."); + + try + { + int p = Int32.Parse(uri.Substring(colon + 1, root - colon - 1)); + if (p <= 0 || p >= 65536) + throw new Exception(); + } + catch + { + throw new ArgumentException("Invalid port."); + } + } + else + { + root = uri.IndexOf('/', start_host, length - start_host); + if (root == -1) + throw new ArgumentException("No path specified."); + } + + if (uri[uri.Length - 1] != '/') + throw new ArgumentException("The prefix must end with '/'"); + } + } +} diff --git a/SocketHttpListener/Net/ResponseStream.cs b/SocketHttpListener/Net/ResponseStream.cs new file mode 100644 index 000000000..5949e3817 --- /dev/null +++ b/SocketHttpListener/Net/ResponseStream.cs @@ -0,0 +1,400 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; +using MediaBrowser.Model.Text; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net +{ + // FIXME: Does this buffer the response until Close? + // Update: we send a single packet for the first non-chunked Write + // What happens when we set content-length to X and write X-1 bytes then close? + // what if we don't set content-length at all? + public class ResponseStream : Stream + { + HttpListenerResponse response; + bool disposed; + bool trailer_sent; + Stream stream; + private readonly IMemoryStreamFactory _memoryStreamFactory; + private readonly ITextEncoding _textEncoding; + private readonly IFileSystem _fileSystem; + private readonly IAcceptSocket _socket; + private readonly bool _supportsDirectSocketAccess; + private readonly ILogger _logger; + private readonly IEnvironmentInfo _environment; + + internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger, IEnvironmentInfo environment) + { + this.response = response; + _memoryStreamFactory = memoryStreamFactory; + _textEncoding = textEncoding; + _fileSystem = fileSystem; + _socket = socket; + _supportsDirectSocketAccess = supportsDirectSocketAccess; + _logger = logger; + _environment = environment; + this.stream = stream; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + + protected override void Dispose(bool disposing) + { + if (disposed == false) + { + disposed = true; + using (var ms = GetHeaders(response, _memoryStreamFactory, false)) + { + if (stream.CanWrite) + { + try + { + bool chunked = response.SendChunked; + + if (ms != null) + { + var start = ms.Position; + if (chunked && !trailer_sent) + { + trailer_sent = true; + var bytes = GetChunkSizeBytes(0, true); + ms.Position = ms.Length; + ms.Write(bytes, 0, bytes.Length); + ms.Position = start; + } + + ms.CopyTo(stream); + } + else if (chunked && !trailer_sent) + { + trailer_sent = true; + + var bytes = GetChunkSizeBytes(0, true); + stream.Write(bytes, 0, bytes.Length); + } + } + catch (IOException ex) + { + // Ignore error due to connection reset by peer + } + } + response.Close(); + } + } + + base.Dispose(disposing); + } + + internal static MemoryStream GetHeaders(HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, bool closing) + { + // SendHeaders works on shared headers + lock (response.headers_lock) + { + if (response.HeadersSent) + return null; + var ms = memoryStreamFactory.CreateNew(); + response.SendHeaders(closing, ms); + return ms; + } + } + + public override void Flush() + { + } + + static byte[] crlf = new byte[] { 13, 10 }; + byte[] GetChunkSizeBytes(int size, bool final) + { + string str = String.Format("{0:x}\r\n{1}", size, final ? "\r\n" : ""); + return _textEncoding.GetASCIIEncoding().GetBytes(str); + } + + internal void InternalWrite(byte[] buffer, int offset, int count) + { + stream.Write(buffer, offset, count); + } + + const int MsCopyBufferSize = 81920; + const int StreamCopyToBufferSize = 81920; + public override void Write(byte[] buffer, int offset, int count) + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + if (count == 0) + { + return; + } + + using (var ms = GetHeaders(response, _memoryStreamFactory, false)) + { + bool chunked = response.SendChunked; + if (ms != null) + { + long start = ms.Position; // After the possible preamble for the encoding + ms.Position = ms.Length; + if (chunked) + { + var bytes = GetChunkSizeBytes(count, false); + ms.Write(bytes, 0, bytes.Length); + } + + ms.Write(buffer, offset, count); + + if (chunked) + { + ms.Write(crlf, 0, 2); + } + + ms.Position = start; + ms.CopyTo(stream, MsCopyBufferSize); + + return; + } + + if (chunked) + { + var bytes = GetChunkSizeBytes(count, false); + stream.Write(bytes, 0, bytes.Length); + } + + stream.Write(buffer, offset, count); + + if (chunked) + stream.Write(crlf, 0, 2); + } + } + + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (disposed) + throw new ObjectDisposedException(GetType().ToString()); + + if (count == 0) + { + return; + } + + using (var ms = GetHeaders(response, _memoryStreamFactory, false)) + { + bool chunked = response.SendChunked; + if (ms != null) + { + long start = ms.Position; // After the possible preamble for the encoding + ms.Position = ms.Length; + if (chunked) + { + var bytes = GetChunkSizeBytes(count, false); + ms.Write(bytes, 0, bytes.Length); + } + + ms.Write(buffer, offset, count); + + if (chunked) + { + ms.Write(crlf, 0, 2); + } + + ms.Position = start; + await ms.CopyToAsync(stream, MsCopyBufferSize, cancellationToken).ConfigureAwait(false); + + return; + } + + if (chunked) + { + var bytes = GetChunkSizeBytes(count, false); + stream.Write(bytes, 0, bytes.Length); + } + + await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + + if (chunked) + stream.Write(crlf, 0, 2); + } + } + + public override int Read([In, Out] byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + private bool EnableSendFileWithSocket + { + get { return false; } + } + + public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked && response.ContentLength64 > 8192) + { + if (EnableSendFileWithSocket) + { + return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken); + } + } + return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); + } + + private readonly byte[] _emptyBuffer = new byte[] { }; + private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + var ms = GetHeaders(response, _memoryStreamFactory, false); + + byte[] preBuffer; + if (ms != null) + { + using (var msCopy = new MemoryStream()) + { + ms.CopyTo(msCopy); + preBuffer = msCopy.ToArray(); + } + } + else + { + return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); + } + + _logger.Info("Socket sending file {0} {1}", path, response.ContentLength64); + return _socket.SendFile(path, preBuffer, _emptyBuffer, cancellationToken); + } + + private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + var allowAsync = _environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; + + var fileOpenOptions = offset > 0 + ? FileOpenOptions.RandomAccess + : FileOpenOptions.SequentialScan; + + if (allowAsync) + { + fileOpenOptions |= FileOpenOptions.Asynchronous; + } + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + + using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions)) + { + if (offset > 0) + { + fs.Position = offset; + } + + var targetStream = this; + + if (count > 0) + { + if (allowAsync) + { + await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + } + else + { + await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + } + } + else + { + if (allowAsync) + { + await fs.CopyToAsync(targetStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false); + } + else + { + fs.CopyTo(targetStream, StreamCopyToBufferSize); + } + } + } + } + + private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) + { + var array = new byte[StreamCopyToBufferSize]; + int bytesRead; + + while ((bytesRead = source.Read(array, 0, array.Length)) != 0) + { + var bytesToWrite = Math.Min(bytesRead, copyLength); + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } + + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; + } + } + } + + private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) + { + var array = new byte[StreamCopyToBufferSize]; + int bytesRead; + + while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) + { + var bytesToWrite = Math.Min(bytesRead, copyLength); + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } + + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; + } + } + } + } +} diff --git a/SocketHttpListener/Net/WebHeaderCollection.cs b/SocketHttpListener/Net/WebHeaderCollection.cs new file mode 100644 index 000000000..d20f99b9b --- /dev/null +++ b/SocketHttpListener/Net/WebHeaderCollection.cs @@ -0,0 +1,391 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Net; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; +using MediaBrowser.Model.Services; + +namespace SocketHttpListener.Net +{ + [ComVisible(true)] + public class WebHeaderCollection : QueryParamCollection + { + [Flags] + internal enum HeaderInfo + { + Request = 1, + Response = 1 << 1, + MultiValue = 1 << 10 + } + + static readonly bool[] allowed_chars = { + false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, true, false, true, true, true, true, false, false, false, true, + true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, false, + false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + false, true, false + }; + + static readonly Dictionary headers; + HeaderInfo? headerRestriction; + HeaderInfo? headerConsistency; + + static WebHeaderCollection() + { + headers = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "Allow", HeaderInfo.MultiValue }, + { "Accept", HeaderInfo.Request | HeaderInfo.MultiValue }, + { "Accept-Charset", HeaderInfo.MultiValue }, + { "Accept-Encoding", HeaderInfo.MultiValue }, + { "Accept-Language", HeaderInfo.MultiValue }, + { "Accept-Ranges", HeaderInfo.MultiValue }, + { "Age", HeaderInfo.Response }, + { "Authorization", HeaderInfo.MultiValue }, + { "Cache-Control", HeaderInfo.MultiValue }, + { "Cookie", HeaderInfo.MultiValue }, + { "Connection", HeaderInfo.Request | HeaderInfo.MultiValue }, + { "Content-Encoding", HeaderInfo.MultiValue }, + { "Content-Length", HeaderInfo.Request | HeaderInfo.Response }, + { "Content-Type", HeaderInfo.Request }, + { "Content-Language", HeaderInfo.MultiValue }, + { "Date", HeaderInfo.Request }, + { "Expect", HeaderInfo.Request | HeaderInfo.MultiValue}, + { "Host", HeaderInfo.Request }, + { "If-Match", HeaderInfo.MultiValue }, + { "If-Modified-Since", HeaderInfo.Request }, + { "If-None-Match", HeaderInfo.MultiValue }, + { "Keep-Alive", HeaderInfo.Response }, + { "Pragma", HeaderInfo.MultiValue }, + { "Proxy-Authenticate", HeaderInfo.MultiValue }, + { "Proxy-Authorization", HeaderInfo.MultiValue }, + { "Proxy-Connection", HeaderInfo.Request | HeaderInfo.MultiValue }, + { "Range", HeaderInfo.Request | HeaderInfo.MultiValue }, + { "Referer", HeaderInfo.Request }, + { "Set-Cookie", HeaderInfo.MultiValue }, + { "Set-Cookie2", HeaderInfo.MultiValue }, + { "Server", HeaderInfo.Response }, + { "TE", HeaderInfo.MultiValue }, + { "Trailer", HeaderInfo.MultiValue }, + { "Transfer-Encoding", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo.MultiValue }, + { "Translate", HeaderInfo.Request | HeaderInfo.Response }, + { "Upgrade", HeaderInfo.MultiValue }, + { "User-Agent", HeaderInfo.Request }, + { "Vary", HeaderInfo.MultiValue }, + { "Via", HeaderInfo.MultiValue }, + { "Warning", HeaderInfo.MultiValue }, + { "WWW-Authenticate", HeaderInfo.Response | HeaderInfo. MultiValue }, + { "SecWebSocketAccept", HeaderInfo.Response }, + { "SecWebSocketExtensions", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo. MultiValue }, + { "SecWebSocketKey", HeaderInfo.Request }, + { "Sec-WebSocket-Protocol", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo. MultiValue }, + { "SecWebSocketVersion", HeaderInfo.Response | HeaderInfo. MultiValue } + }; + } + + // Methods + + public void Add(string header) + { + if (header == null) + throw new ArgumentNullException("header"); + int pos = header.IndexOf(':'); + if (pos == -1) + throw new ArgumentException("no colon found", "header"); + + this.Add(header.Substring(0, pos), header.Substring(pos + 1)); + } + + public override void Add(string name, string value) + { + if (name == null) + throw new ArgumentNullException("name"); + + ThrowIfRestricted(name); + this.AddWithoutValidate(name, value); + } + + protected void AddWithoutValidate(string headerName, string headerValue) + { + if (!IsHeaderName(headerName)) + throw new ArgumentException("invalid header name: " + headerName, "headerName"); + if (headerValue == null) + headerValue = String.Empty; + else + headerValue = headerValue.Trim(); + if (!IsHeaderValue(headerValue)) + throw new ArgumentException("invalid header value: " + headerValue, "headerValue"); + + AddValue(headerName, headerValue); + } + + internal void AddValue(string headerName, string headerValue) + { + base.Add(headerName, headerValue); + } + + internal string[] GetValues_internal(string header, bool split) + { + if (header == null) + throw new ArgumentNullException("header"); + + string[] values = base.GetValues(header); + if (values == null || values.Length == 0) + return null; + + if (split && IsMultiValue(header)) + { + List separated = null; + foreach (var value in values) + { + if (value.IndexOf(',') < 0) + { + if (separated != null) + separated.Add(value); + + continue; + } + + if (separated == null) + { + separated = new List(values.Length + 1); + foreach (var v in values) + { + if (v == value) + break; + + separated.Add(v); + } + } + + var slices = value.Split(','); + var slices_length = slices.Length; + if (value[value.Length - 1] == ',') + --slices_length; + + for (int i = 0; i < slices_length; ++i) + { + separated.Add(slices[i].Trim()); + } + } + + if (separated != null) + return separated.ToArray(); + } + + return values; + } + + public override string[] GetValues(string header) + { + return GetValues_internal(header, true); + } + + public override string[] GetValues(int index) + { + string[] values = base.GetValues(index); + + if (values == null || values.Length == 0) + { + return null; + } + + return values; + } + + public static bool IsRestricted(string headerName) + { + return IsRestricted(headerName, false); + } + + public static bool IsRestricted(string headerName, bool response) + { + if (headerName == null) + throw new ArgumentNullException("headerName"); + + if (headerName.Length == 0) + throw new ArgumentException("empty string", "headerName"); + + if (!IsHeaderName(headerName)) + throw new ArgumentException("Invalid character in header"); + + HeaderInfo info; + if (!headers.TryGetValue(headerName, out info)) + return false; + + var flag = response ? HeaderInfo.Response : HeaderInfo.Request; + return (info & flag) != 0; + } + + public override void Set(string name, string value) + { + if (name == null) + throw new ArgumentNullException("name"); + if (!IsHeaderName(name)) + throw new ArgumentException("invalid header name"); + if (value == null) + value = String.Empty; + else + value = value.Trim(); + if (!IsHeaderValue(value)) + throw new ArgumentException("invalid header value"); + + ThrowIfRestricted(name); + base.Set(name, value); + } + + internal string ToStringMultiValue() + { + StringBuilder sb = new StringBuilder(); + + int count = base.Count; + for (int i = 0; i < count; i++) + { + string key = GetKey(i); + if (IsMultiValue(key)) + { + foreach (string v in GetValues(i)) + { + sb.Append(key) + .Append(": ") + .Append(v) + .Append("\r\n"); + } + } + else + { + sb.Append(key) + .Append(": ") + .Append(Get(i)) + .Append("\r\n"); + } + } + return sb.Append("\r\n").ToString(); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + int count = base.Count; + for (int i = 0; i < count; i++) + sb.Append(GetKey(i)) + .Append(": ") + .Append(Get(i)) + .Append("\r\n"); + + return sb.Append("\r\n").ToString(); + } + + + // Internal Methods + + // With this we don't check for invalid characters in header. See bug #55994. + internal void SetInternal(string header) + { + int pos = header.IndexOf(':'); + if (pos == -1) + throw new ArgumentException("no colon found", "header"); + + SetInternal(header.Substring(0, pos), header.Substring(pos + 1)); + } + + internal void SetInternal(string name, string value) + { + if (value == null) + value = String.Empty; + else + value = value.Trim(); + if (!IsHeaderValue(value)) + throw new ArgumentException("invalid header value"); + + if (IsMultiValue(name)) + { + base.Add(name, value); + } + else + { + base.Remove(name); + base.Set(name, value); + } + } + + // Private Methods + + public override int Remove(string name) + { + ThrowIfRestricted(name); + return base.Remove(name); + } + + protected void ThrowIfRestricted(string headerName) + { + if (!headerRestriction.HasValue) + return; + + HeaderInfo info; + if (!headers.TryGetValue(headerName, out info)) + return; + + if ((info & headerRestriction.Value) != 0) + throw new ArgumentException("This header must be modified with the appropriate property."); + } + + internal static bool IsMultiValue(string headerName) + { + if (headerName == null) + return false; + + HeaderInfo info; + return headers.TryGetValue(headerName, out info) && (info & HeaderInfo.MultiValue) != 0; + } + + internal static bool IsHeaderValue(string value) + { + // TEXT any 8 bit value except CTL's (0-31 and 127) + // but including \r\n space and \t + // after a newline at least one space or \t must follow + // certain header fields allow comments () + + int len = value.Length; + for (int i = 0; i < len; i++) + { + char c = value[i]; + if (c == 127) + return false; + if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t')) + return false; + if (c == '\n' && ++i < len) + { + c = value[i]; + if (c != ' ' && c != '\t') + return false; + } + } + + return true; + } + + internal static bool IsHeaderName(string name) + { + if (name == null || name.Length == 0) + return false; + + int len = name.Length; + for (int i = 0; i < len; i++) + { + char c = name[i]; + if (c > 126 || !allowed_chars[c]) + return false; + } + + return true; + } + } +} diff --git a/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs new file mode 100644 index 000000000..034ac17d2 --- /dev/null +++ b/SocketHttpListener/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -0,0 +1,348 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Net; +using System.Security.Principal; +using MediaBrowser.Model.Cryptography; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Services; +using SocketHttpListener.Primitives; + +namespace SocketHttpListener.Net.WebSockets +{ + /// + /// Provides the properties used to access the information in a WebSocket connection request + /// received by the . + /// + /// + /// + public class HttpListenerWebSocketContext : WebSocketContext + { + #region Private Fields + + private HttpListenerContext _context; + private WebSocket _websocket; + + #endregion + + #region Internal Constructors + + internal HttpListenerWebSocketContext( + HttpListenerContext context, string protocol, ICryptoProvider cryptoProvider, IMemoryStreamFactory memoryStreamFactory) + { + _context = context; + _websocket = new WebSocket(this, protocol, cryptoProvider, memoryStreamFactory); + } + + #endregion + + #region Internal Properties + + internal Stream Stream + { + get + { + return _context.Connection.Stream; + } + } + + #endregion + + #region Public Properties + + /// + /// Gets the HTTP cookies included in the request. + /// + /// + /// A that contains the cookies. + /// + public override CookieCollection CookieCollection + { + get + { + return _context.Request.Cookies; + } + } + + /// + /// Gets the HTTP headers included in the request. + /// + /// + /// A that contains the headers. + /// + public override QueryParamCollection Headers + { + get + { + return _context.Request.Headers; + } + } + + /// + /// Gets the value of the Host header included in the request. + /// + /// + /// A that represents the value of the Host header. + /// + public override string Host + { + get + { + return _context.Request.Headers["Host"]; + } + } + + /// + /// Gets a value indicating whether the client is authenticated. + /// + /// + /// true if the client is authenticated; otherwise, false. + /// + public override bool IsAuthenticated + { + get + { + return _context.Request.IsAuthenticated; + } + } + + /// + /// Gets a value indicating whether the client connected from the local computer. + /// + /// + /// true if the client connected from the local computer; otherwise, false. + /// + public override bool IsLocal + { + get + { + return _context.Request.IsLocal; + } + } + + /// + /// Gets a value indicating whether the WebSocket connection is secured. + /// + /// + /// true if the connection is secured; otherwise, false. + /// + public override bool IsSecureConnection + { + get + { + return _context.Connection.IsSecure; + } + } + + /// + /// Gets a value indicating whether the request is a WebSocket connection request. + /// + /// + /// true if the request is a WebSocket connection request; otherwise, false. + /// + public override bool IsWebSocketRequest + { + get + { + return _context.Request.IsWebSocketRequest; + } + } + + /// + /// Gets the value of the Origin header included in the request. + /// + /// + /// A that represents the value of the Origin header. + /// + public override string Origin + { + get + { + return _context.Request.Headers["Origin"]; + } + } + + /// + /// Gets the query string included in the request. + /// + /// + /// A that contains the query string parameters. + /// + public override QueryParamCollection QueryString + { + get + { + return _context.Request.QueryString; + } + } + + /// + /// Gets the URI requested by the client. + /// + /// + /// A that represents the requested URI. + /// + public override Uri RequestUri + { + get + { + return _context.Request.Url; + } + } + + /// + /// Gets the value of the Sec-WebSocket-Key header included in the request. + /// + /// + /// This property provides a part of the information used by the server to prove that it + /// received a valid WebSocket connection request. + /// + /// + /// A that represents the value of the Sec-WebSocket-Key header. + /// + public override string SecWebSocketKey + { + get + { + return _context.Request.Headers["Sec-WebSocket-Key"]; + } + } + + /// + /// Gets the values of the Sec-WebSocket-Protocol header included in the request. + /// + /// + /// This property represents the subprotocols requested by the client. + /// + /// + /// An instance that provides + /// an enumerator which supports the iteration over the values of the Sec-WebSocket-Protocol + /// header. + /// + public override IEnumerable SecWebSocketProtocols + { + get + { + var protocols = _context.Request.Headers["Sec-WebSocket-Protocol"]; + if (protocols != null) + foreach (var protocol in protocols.Split(',')) + yield return protocol.Trim(); + } + } + + /// + /// Gets the value of the Sec-WebSocket-Version header included in the request. + /// + /// + /// This property represents the WebSocket protocol version. + /// + /// + /// A that represents the value of the Sec-WebSocket-Version header. + /// + public override string SecWebSocketVersion + { + get + { + return _context.Request.Headers["Sec-WebSocket-Version"]; + } + } + + /// + /// Gets the server endpoint as an IP address and a port number. + /// + /// + /// + public override IpEndPointInfo ServerEndPoint + { + get + { + return _context.Connection.LocalEndPoint; + } + } + + /// + /// Gets the client information (identity, authentication, and security roles). + /// + /// + /// A that represents the client information. + /// + public override IPrincipal User + { + get + { + return _context.User; + } + } + + /// + /// Gets the client endpoint as an IP address and a port number. + /// + /// + /// + public override IpEndPointInfo UserEndPoint + { + get + { + return _context.Connection.RemoteEndPoint; + } + } + + /// + /// Gets the instance used for two-way communication + /// between client and server. + /// + /// + /// A . + /// + public override WebSocket WebSocket + { + get + { + return _websocket; + } + } + + #endregion + + #region Internal Methods + + internal void Close() + { + try + { + _context.Connection.Close(true); + } + catch + { + // catch errors sending the closing handshake + } + } + + internal void Close(HttpStatusCode code) + { + _context.Response.StatusCode = (int)code; + _context.Response.OutputStream.Dispose(); + } + + #endregion + + #region Public Methods + + /// + /// Returns a that represents the current + /// . + /// + /// + /// A that represents the current + /// . + /// + public override string ToString() + { + return _context.Request.ToString(); + } + + #endregion + } +} diff --git a/SocketHttpListener/Net/WebSockets/WebSocketContext.cs b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs new file mode 100644 index 000000000..3ffa6e639 --- /dev/null +++ b/SocketHttpListener/Net/WebSockets/WebSocketContext.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Net; +using System.Security.Principal; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Services; + +namespace SocketHttpListener.Net.WebSockets +{ + /// + /// Exposes the properties used to access the information in a WebSocket connection request. + /// + /// + /// The WebSocketContext class is an abstract class. + /// + public abstract class WebSocketContext + { + #region Protected Constructors + + /// + /// Initializes a new instance of the class. + /// + protected WebSocketContext() + { + } + + #endregion + + #region Public Properties + + /// + /// Gets the HTTP cookies included in the request. + /// + /// + /// A that contains the cookies. + /// + public abstract CookieCollection CookieCollection { get; } + + /// + /// Gets the HTTP headers included in the request. + /// + /// + /// A that contains the headers. + /// + public abstract QueryParamCollection Headers { get; } + + /// + /// Gets the value of the Host header included in the request. + /// + /// + /// A that represents the value of the Host header. + /// + public abstract string Host { get; } + + /// + /// Gets a value indicating whether the client is authenticated. + /// + /// + /// true if the client is authenticated; otherwise, false. + /// + public abstract bool IsAuthenticated { get; } + + /// + /// Gets a value indicating whether the client connected from the local computer. + /// + /// + /// true if the client connected from the local computer; otherwise, false. + /// + public abstract bool IsLocal { get; } + + /// + /// Gets a value indicating whether the WebSocket connection is secured. + /// + /// + /// true if the connection is secured; otherwise, false. + /// + public abstract bool IsSecureConnection { get; } + + /// + /// Gets a value indicating whether the request is a WebSocket connection request. + /// + /// + /// true if the request is a WebSocket connection request; otherwise, false. + /// + public abstract bool IsWebSocketRequest { get; } + + /// + /// Gets the value of the Origin header included in the request. + /// + /// + /// A that represents the value of the Origin header. + /// + public abstract string Origin { get; } + + /// + /// Gets the query string included in the request. + /// + /// + /// A that contains the query string parameters. + /// + public abstract QueryParamCollection QueryString { get; } + + /// + /// Gets the URI requested by the client. + /// + /// + /// A that represents the requested URI. + /// + public abstract Uri RequestUri { get; } + + /// + /// Gets the value of the Sec-WebSocket-Key header included in the request. + /// + /// + /// This property provides a part of the information used by the server to prove that it + /// received a valid WebSocket connection request. + /// + /// + /// A that represents the value of the Sec-WebSocket-Key header. + /// + public abstract string SecWebSocketKey { get; } + + /// + /// Gets the values of the Sec-WebSocket-Protocol header included in the request. + /// + /// + /// This property represents the subprotocols requested by the client. + /// + /// + /// An instance that provides + /// an enumerator which supports the iteration over the values of the Sec-WebSocket-Protocol + /// header. + /// + public abstract IEnumerable SecWebSocketProtocols { get; } + + /// + /// Gets the value of the Sec-WebSocket-Version header included in the request. + /// + /// + /// This property represents the WebSocket protocol version. + /// + /// + /// A that represents the value of the Sec-WebSocket-Version header. + /// + public abstract string SecWebSocketVersion { get; } + + /// + /// Gets the server endpoint as an IP address and a port number. + /// + /// + /// A that represents the server endpoint. + /// + public abstract IpEndPointInfo ServerEndPoint { get; } + + /// + /// Gets the client information (identity, authentication, and security roles). + /// + /// + /// A that represents the client information. + /// + public abstract IPrincipal User { get; } + + /// + /// Gets the client endpoint as an IP address and a port number. + /// + /// + /// A that represents the client endpoint. + /// + public abstract IpEndPointInfo UserEndPoint { get; } + + /// + /// Gets the instance used for two-way communication + /// between client and server. + /// + /// + /// A . + /// + public abstract WebSocket WebSocket { get; } + + #endregion + } +} -- cgit v1.2.3 From 71f7fc4e116f32a20c63ddbb17844a81283a6ba4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 24 May 2017 15:39:59 -0400 Subject: 3.2.17.12 --- .../SocketSharp/WebSocketSharpResponse.cs | 10 +- SharedVersion.cs | 2 +- SocketHttpListener/Net/HttpConnection.cs | 4 +- SocketHttpListener/Net/HttpListenerRequest.cs | 2 +- SocketHttpListener/Net/HttpListenerResponse.cs | 2 +- .../Net/HttpResponseStream.Managed.cs | 459 +++++++++++++++++++++ SocketHttpListener/Net/HttpResponseStream.cs | 139 +++++++ SocketHttpListener/Net/ResponseStream.cs | 400 ------------------ SocketHttpListener/SocketHttpListener.csproj | 3 +- 9 files changed, 608 insertions(+), 413 deletions(-) create mode 100644 SocketHttpListener/Net/HttpResponseStream.Managed.cs create mode 100644 SocketHttpListener/Net/HttpResponseStream.cs delete mode 100644 SocketHttpListener/Net/ResponseStream.cs (limited to 'SocketHttpListener/Net') diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index 9e58ee57c..d6762d94b 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs @@ -114,15 +114,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp var outputStream = response.OutputStream; // This is needed with compression - if (outputStream is ResponseStream) - { - //if (!string.IsNullOrWhiteSpace(GetHeader("Content-Encoding"))) - { - outputStream.Flush(); - } + outputStream.Flush(); + outputStream.Dispose(); - outputStream.Dispose(); - } response.Close(); } catch (Exception ex) diff --git a/SharedVersion.cs b/SharedVersion.cs index 1564e4a41..e2671c988 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.17.11")] +[assembly: AssemblyVersion("3.2.17.12")] diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs index 848b80f99..627b671bf 100644 --- a/SocketHttpListener/Net/HttpConnection.cs +++ b/SocketHttpListener/Net/HttpConnection.cs @@ -218,7 +218,9 @@ namespace SocketHttpListener.Net var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure; - o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment); + //o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment); + + o_stream = new HttpResponseStream(stream, context.Response, false, _memoryStreamFactory, sock, supportsDirectSocketAccess, _environment, _fileSystem); } return o_stream; } diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs index cfbd49203..6a99eb078 100644 --- a/SocketHttpListener/Net/HttpListenerRequest.cs +++ b/SocketHttpListener/Net/HttpListenerRequest.cs @@ -181,7 +181,7 @@ namespace SocketHttpListener.Net if (String.Compare(Headers["Expect"], "100-continue", StringComparison.OrdinalIgnoreCase) == 0) { - var output = (ResponseStream)context.Connection.GetResponseStream(true); + var output = (HttpResponseStream)context.Connection.GetResponseStream(true); var _100continue = _textEncoding.GetASCIIEncoding().GetBytes("HTTP/1.1 100 Continue\r\n\r\n"); diff --git a/SocketHttpListener/Net/HttpListenerResponse.cs b/SocketHttpListener/Net/HttpListenerResponse.cs index 3cb6a0d75..185454ef6 100644 --- a/SocketHttpListener/Net/HttpListenerResponse.cs +++ b/SocketHttpListener/Net/HttpListenerResponse.cs @@ -519,7 +519,7 @@ namespace SocketHttpListener.Net public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) { - return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken); + return ((HttpResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken); } } } \ No newline at end of file diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs new file mode 100644 index 000000000..0a9efccb2 --- /dev/null +++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs @@ -0,0 +1,459 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Runtime.ExceptionServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.System; + +namespace SocketHttpListener.Net +{ + // Licensed to the .NET Foundation under one or more agreements. + // See the LICENSE file in the project root for more information. + // + // System.Net.ResponseStream + // + // Author: + // Gonzalo Paniagua Javier (gonzalo@novell.com) + // + // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + // + // Permission is hereby granted, free of charge, to any person obtaining + // a copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to + // permit persons to whom the Software is furnished to do so, subject to + // the following conditions: + // + // The above copyright notice and this permission notice shall be + // included in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + // + + internal partial class HttpResponseStream : Stream + { + private HttpListenerResponse _response; + private bool _ignore_errors; + private bool _trailer_sent; + private Stream _stream; + private readonly IMemoryStreamFactory _memoryStreamFactory; + private readonly IAcceptSocket _socket; + private readonly bool _supportsDirectSocketAccess; + private readonly IEnvironmentInfo _environment; + private readonly IFileSystem _fileSystem; + internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, IAcceptSocket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem) + { + _response = response; + _ignore_errors = ignore_errors; + _memoryStreamFactory = memoryStreamFactory; + _socket = socket; + _supportsDirectSocketAccess = supportsDirectSocketAccess; + _environment = environment; + _fileSystem = fileSystem; + _stream = stream; + } + + private void DisposeCore() + { + byte[] bytes = null; + MemoryStream ms = GetHeaders(true); + bool chunked = _response.SendChunked; + if (_stream.CanWrite) + { + try + { + if (ms != null) + { + long start = ms.Position; + if (chunked && !_trailer_sent) + { + bytes = GetChunkSizeBytes(0, true); + ms.Position = ms.Length; + ms.Write(bytes, 0, bytes.Length); + } + InternalWrite(ms.GetBuffer(), (int)start, (int)(ms.Length - start)); + _trailer_sent = true; + } + else if (chunked && !_trailer_sent) + { + bytes = GetChunkSizeBytes(0, true); + InternalWrite(bytes, 0, bytes.Length); + _trailer_sent = true; + } + } + catch (HttpListenerException) + { + // Ignore error due to connection reset by peer + } + } + _response.Close(); + } + + internal async Task WriteWebSocketHandshakeHeadersAsync() + { + if (_closed) + throw new ObjectDisposedException(GetType().ToString()); + + if (_stream.CanWrite) + { + MemoryStream ms = GetHeaders(closing: false, isWebSocketHandshake: true); + bool chunked = _response.SendChunked; + + long start = ms.Position; + if (chunked) + { + byte[] bytes = GetChunkSizeBytes(0, true); + ms.Position = ms.Length; + ms.Write(bytes, 0, bytes.Length); + } + + await InternalWriteAsync(ms.GetBuffer(), (int)start, (int)(ms.Length - start)).ConfigureAwait(false); + await _stream.FlushAsync().ConfigureAwait(false); + } + } + + private MemoryStream GetHeaders(bool closing, bool isWebSocketHandshake = false) + { + // SendHeaders works on shared headers + lock (_response.headers_lock) + { + if (_response.HeadersSent) + return null; + var ms = _memoryStreamFactory.CreateNew(); + _response.SendHeaders(closing, ms); + return ms; + } + + //lock (_response._headersLock) + //{ + // if (_response.SentHeaders) + // { + // return null; + // } + + // MemoryStream ms = new MemoryStream(); + // _response.SendHeaders(closing, ms, isWebSocketHandshake); + // return ms; + //} + } + + private static byte[] s_crlf = new byte[] { 13, 10 }; + private static byte[] GetChunkSizeBytes(int size, bool final) + { + string str = String.Format("{0:x}\r\n{1}", size, final ? "\r\n" : ""); + return Encoding.ASCII.GetBytes(str); + } + + internal void InternalWrite(byte[] buffer, int offset, int count) + { + if (_ignore_errors) + { + try + { + _stream.Write(buffer, offset, count); + } + catch { } + } + else + { + try + { + _stream.Write(buffer, offset, count); + } + catch (IOException ex) + { + throw new HttpListenerException(ex.HResult, ex.Message); + } + } + } + + internal Task InternalWriteAsync(byte[] buffer, int offset, int count) => + _ignore_errors ? InternalWriteIgnoreErrorsAsync(buffer, offset, count) : _stream.WriteAsync(buffer, offset, count); + + private async Task InternalWriteIgnoreErrorsAsync(byte[] buffer, int offset, int count) + { + try { await _stream.WriteAsync(buffer, offset, count).ConfigureAwait(false); } + catch { } + } + + private void WriteCore(byte[] buffer, int offset, int size) + { + if (size == 0) + return; + + byte[] bytes = null; + MemoryStream ms = GetHeaders(false); + bool chunked = _response.SendChunked; + if (ms != null) + { + long start = ms.Position; // After the possible preamble for the encoding + ms.Position = ms.Length; + if (chunked) + { + bytes = GetChunkSizeBytes(size, false); + ms.Write(bytes, 0, bytes.Length); + } + + int new_count = Math.Min(size, 16384 - (int)ms.Position + (int)start); + ms.Write(buffer, offset, new_count); + size -= new_count; + offset += new_count; + InternalWrite(ms.GetBuffer(), (int)start, (int)(ms.Length - start)); + ms.SetLength(0); + ms.Capacity = 0; // 'dispose' the buffer in ms. + } + else if (chunked) + { + bytes = GetChunkSizeBytes(size, false); + InternalWrite(bytes, 0, bytes.Length); + } + + if (size > 0) + InternalWrite(buffer, offset, size); + if (chunked) + InternalWrite(s_crlf, 0, 2); + } + + private IAsyncResult BeginWriteCore(byte[] buffer, int offset, int size, AsyncCallback cback, object state) + { + if (_closed) + { + HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this); + ares._callback = cback; + ares._state = state; + ares.Complete(); + return ares; + } + + byte[] bytes = null; + MemoryStream ms = GetHeaders(false); + bool chunked = _response.SendChunked; + if (ms != null) + { + long start = ms.Position; + ms.Position = ms.Length; + if (chunked) + { + bytes = GetChunkSizeBytes(size, false); + ms.Write(bytes, 0, bytes.Length); + } + ms.Write(buffer, offset, size); + buffer = ms.GetBuffer(); + offset = (int)start; + size = (int)(ms.Position - start); + } + else if (chunked) + { + bytes = GetChunkSizeBytes(size, false); + InternalWrite(bytes, 0, bytes.Length); + } + + try + { + return _stream.BeginWrite(buffer, offset, size, cback, state); + } + catch (IOException ex) + { + if (_ignore_errors) + { + HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this); + ares._callback = cback; + ares._state = state; + ares.Complete(); + return ares; + } + else + { + throw new HttpListenerException(ex.HResult, ex.Message); + } + } + } + + private void EndWriteCore(IAsyncResult asyncResult) + { + if (_closed) + return; + + if (_ignore_errors) + { + try + { + _stream.EndWrite(asyncResult); + if (_response.SendChunked) + _stream.Write(s_crlf, 0, 2); + } + catch { } + } + else + { + try + { + _stream.EndWrite(asyncResult); + if (_response.SendChunked) + _stream.Write(s_crlf, 0, 2); + } + catch (IOException ex) + { + // NetworkStream wraps exceptions in IOExceptions; if the underlying socket operation + // failed because of invalid arguments or usage, propagate that error. Otherwise + // wrap the whole thing in an HttpListenerException. This is all to match Windows behavior. + if (ex.InnerException is ArgumentException || ex.InnerException is InvalidOperationException) + { + throw ex.InnerException; + } + + throw new HttpListenerException(ex.HResult, ex.Message); + } + } + } + + private bool EnableSendFileWithSocket + { + get { return false; } + } + + public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !_response.SendChunked && _response.ContentLength64 > 8192) + { + if (EnableSendFileWithSocket) + { + return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken); + } + } + return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); + } + + private readonly byte[] _emptyBuffer = new byte[] { }; + private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + var ms = GetHeaders(false); + + byte[] preBuffer; + if (ms != null) + { + using (var msCopy = new MemoryStream()) + { + ms.CopyTo(msCopy); + preBuffer = msCopy.ToArray(); + } + } + else + { + return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); + } + + //_logger.Info("Socket sending file {0} {1}", path, response.ContentLength64); + return _socket.SendFile(path, preBuffer, _emptyBuffer, cancellationToken); + } + + const int StreamCopyToBufferSize = 81920; + private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) + { + var allowAsync = _environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; + + var fileOpenOptions = offset > 0 + ? FileOpenOptions.RandomAccess + : FileOpenOptions.SequentialScan; + + if (allowAsync) + { + fileOpenOptions |= FileOpenOptions.Asynchronous; + } + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + + using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions)) + { + if (offset > 0) + { + fs.Position = offset; + } + + var targetStream = this; + + if (count > 0) + { + if (allowAsync) + { + await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + } + else + { + await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false); + } + } + else + { + if (allowAsync) + { + await fs.CopyToAsync(targetStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false); + } + else + { + fs.CopyTo(targetStream, StreamCopyToBufferSize); + } + } + } + } + + private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) + { + var array = new byte[StreamCopyToBufferSize]; + int bytesRead; + + while ((bytesRead = source.Read(array, 0, array.Length)) != 0) + { + var bytesToWrite = Math.Min(bytesRead, copyLength); + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } + + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; + } + } + } + + private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) + { + var array = new byte[StreamCopyToBufferSize]; + int bytesRead; + + while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) + { + var bytesToWrite = Math.Min(bytesRead, copyLength); + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } + + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; + } + } + } + } +} diff --git a/SocketHttpListener/Net/HttpResponseStream.cs b/SocketHttpListener/Net/HttpResponseStream.cs new file mode 100644 index 000000000..f7140be66 --- /dev/null +++ b/SocketHttpListener/Net/HttpResponseStream.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace SocketHttpListener.Net +{ + internal sealed partial class HttpResponseStream : Stream + { + private bool _closed; + internal bool Closed => _closed; + + public override bool CanRead => false; + public override bool CanSeek => false; + public override bool CanWrite => true; + + public override void Flush() { } + public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + public override long Length + { + get + { + throw new NotImplementedException(); + } + } + + public override long Position + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return base.BeginRead(buffer, offset, count, callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return base.EndRead(asyncResult); + } + + public override void Write(byte[] buffer, int offset, int size) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (size < 0 || size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + if (_closed) + { + return; + } + + WriteCore(buffer, offset, size); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0 || offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (size < 0 || size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + return BeginWriteCore(buffer, offset, size, callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + if (asyncResult == null) + { + throw new ArgumentNullException(nameof(asyncResult)); + } + + EndWriteCore(asyncResult); + } + + protected override void Dispose(bool disposing) + { + try + { + if (disposing) + { + if (_closed) + { + return; + } + _closed = true; + DisposeCore(); + } + } + finally + { + base.Dispose(disposing); + } + } + } +} diff --git a/SocketHttpListener/Net/ResponseStream.cs b/SocketHttpListener/Net/ResponseStream.cs deleted file mode 100644 index 5949e3817..000000000 --- a/SocketHttpListener/Net/ResponseStream.cs +++ /dev/null @@ -1,400 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.System; -using MediaBrowser.Model.Text; -using SocketHttpListener.Primitives; - -namespace SocketHttpListener.Net -{ - // FIXME: Does this buffer the response until Close? - // Update: we send a single packet for the first non-chunked Write - // What happens when we set content-length to X and write X-1 bytes then close? - // what if we don't set content-length at all? - public class ResponseStream : Stream - { - HttpListenerResponse response; - bool disposed; - bool trailer_sent; - Stream stream; - private readonly IMemoryStreamFactory _memoryStreamFactory; - private readonly ITextEncoding _textEncoding; - private readonly IFileSystem _fileSystem; - private readonly IAcceptSocket _socket; - private readonly bool _supportsDirectSocketAccess; - private readonly ILogger _logger; - private readonly IEnvironmentInfo _environment; - - internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IAcceptSocket socket, bool supportsDirectSocketAccess, ILogger logger, IEnvironmentInfo environment) - { - this.response = response; - _memoryStreamFactory = memoryStreamFactory; - _textEncoding = textEncoding; - _fileSystem = fileSystem; - _socket = socket; - _supportsDirectSocketAccess = supportsDirectSocketAccess; - _logger = logger; - _environment = environment; - this.stream = stream; - } - - public override bool CanRead - { - get { return false; } - } - - public override bool CanSeek - { - get { return false; } - } - - public override bool CanWrite - { - get { return true; } - } - - public override long Length - { - get { throw new NotSupportedException(); } - } - - public override long Position - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - - - protected override void Dispose(bool disposing) - { - if (disposed == false) - { - disposed = true; - using (var ms = GetHeaders(response, _memoryStreamFactory, false)) - { - if (stream.CanWrite) - { - try - { - bool chunked = response.SendChunked; - - if (ms != null) - { - var start = ms.Position; - if (chunked && !trailer_sent) - { - trailer_sent = true; - var bytes = GetChunkSizeBytes(0, true); - ms.Position = ms.Length; - ms.Write(bytes, 0, bytes.Length); - ms.Position = start; - } - - ms.CopyTo(stream); - } - else if (chunked && !trailer_sent) - { - trailer_sent = true; - - var bytes = GetChunkSizeBytes(0, true); - stream.Write(bytes, 0, bytes.Length); - } - } - catch (IOException ex) - { - // Ignore error due to connection reset by peer - } - } - response.Close(); - } - } - - base.Dispose(disposing); - } - - internal static MemoryStream GetHeaders(HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, bool closing) - { - // SendHeaders works on shared headers - lock (response.headers_lock) - { - if (response.HeadersSent) - return null; - var ms = memoryStreamFactory.CreateNew(); - response.SendHeaders(closing, ms); - return ms; - } - } - - public override void Flush() - { - } - - static byte[] crlf = new byte[] { 13, 10 }; - byte[] GetChunkSizeBytes(int size, bool final) - { - string str = String.Format("{0:x}\r\n{1}", size, final ? "\r\n" : ""); - return _textEncoding.GetASCIIEncoding().GetBytes(str); - } - - internal void InternalWrite(byte[] buffer, int offset, int count) - { - stream.Write(buffer, offset, count); - } - - const int MsCopyBufferSize = 81920; - const int StreamCopyToBufferSize = 81920; - public override void Write(byte[] buffer, int offset, int count) - { - if (disposed) - throw new ObjectDisposedException(GetType().ToString()); - - if (count == 0) - { - return; - } - - using (var ms = GetHeaders(response, _memoryStreamFactory, false)) - { - bool chunked = response.SendChunked; - if (ms != null) - { - long start = ms.Position; // After the possible preamble for the encoding - ms.Position = ms.Length; - if (chunked) - { - var bytes = GetChunkSizeBytes(count, false); - ms.Write(bytes, 0, bytes.Length); - } - - ms.Write(buffer, offset, count); - - if (chunked) - { - ms.Write(crlf, 0, 2); - } - - ms.Position = start; - ms.CopyTo(stream, MsCopyBufferSize); - - return; - } - - if (chunked) - { - var bytes = GetChunkSizeBytes(count, false); - stream.Write(bytes, 0, bytes.Length); - } - - stream.Write(buffer, offset, count); - - if (chunked) - stream.Write(crlf, 0, 2); - } - } - - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - if (disposed) - throw new ObjectDisposedException(GetType().ToString()); - - if (count == 0) - { - return; - } - - using (var ms = GetHeaders(response, _memoryStreamFactory, false)) - { - bool chunked = response.SendChunked; - if (ms != null) - { - long start = ms.Position; // After the possible preamble for the encoding - ms.Position = ms.Length; - if (chunked) - { - var bytes = GetChunkSizeBytes(count, false); - ms.Write(bytes, 0, bytes.Length); - } - - ms.Write(buffer, offset, count); - - if (chunked) - { - ms.Write(crlf, 0, 2); - } - - ms.Position = start; - await ms.CopyToAsync(stream, MsCopyBufferSize, cancellationToken).ConfigureAwait(false); - - return; - } - - if (chunked) - { - var bytes = GetChunkSizeBytes(count, false); - stream.Write(bytes, 0, bytes.Length); - } - - await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - - if (chunked) - stream.Write(crlf, 0, 2); - } - } - - public override int Read([In, Out] byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotSupportedException(); - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - private bool EnableSendFileWithSocket - { - get { return false; } - } - - public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) - { - if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked && response.ContentLength64 > 8192) - { - if (EnableSendFileWithSocket) - { - return TransmitFileOverSocket(path, offset, count, fileShareMode, cancellationToken); - } - } - return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); - } - - private readonly byte[] _emptyBuffer = new byte[] { }; - private Task TransmitFileOverSocket(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) - { - var ms = GetHeaders(response, _memoryStreamFactory, false); - - byte[] preBuffer; - if (ms != null) - { - using (var msCopy = new MemoryStream()) - { - ms.CopyTo(msCopy); - preBuffer = msCopy.ToArray(); - } - } - else - { - return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken); - } - - _logger.Info("Socket sending file {0} {1}", path, response.ContentLength64); - return _socket.SendFile(path, preBuffer, _emptyBuffer, cancellationToken); - } - - private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) - { - var allowAsync = _environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; - - var fileOpenOptions = offset > 0 - ? FileOpenOptions.RandomAccess - : FileOpenOptions.SequentialScan; - - if (allowAsync) - { - fileOpenOptions |= FileOpenOptions.Asynchronous; - } - - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - - using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions)) - { - if (offset > 0) - { - fs.Position = offset; - } - - var targetStream = this; - - if (count > 0) - { - if (allowAsync) - { - await CopyToInternalAsync(fs, targetStream, count, cancellationToken).ConfigureAwait(false); - } - else - { - await CopyToInternalAsyncWithSyncRead(fs, targetStream, count, cancellationToken).ConfigureAwait(false); - } - } - else - { - if (allowAsync) - { - await fs.CopyToAsync(targetStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - else - { - fs.CopyTo(targetStream, StreamCopyToBufferSize); - } - } - } - } - - private static async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) - { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - - while ((bytesRead = source.Read(array, 0, array.Length)) != 0) - { - var bytesToWrite = Math.Min(bytesRead, copyLength); - - if (bytesToWrite > 0) - { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - } - - copyLength -= bytesToWrite; - - if (copyLength <= 0) - { - break; - } - } - } - - private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) - { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - - while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) - { - var bytesToWrite = Math.Min(bytesRead, copyLength); - - if (bytesToWrite > 0) - { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - } - - copyLength -= bytesToWrite; - - if (copyLength <= 0) - { - break; - } - } - } - } -} diff --git a/SocketHttpListener/SocketHttpListener.csproj b/SocketHttpListener/SocketHttpListener.csproj index dd2d2cf0f..3be51071c 100644 --- a/SocketHttpListener/SocketHttpListener.csproj +++ b/SocketHttpListener/SocketHttpListener.csproj @@ -70,11 +70,12 @@ + + - -- cgit v1.2.3 From b9be73789b59553731c8d054cd73aa08165fdbca Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 25 May 2017 00:25:51 -0400 Subject: fix plugin loading --- Emby.Common.Implementations/BaseApplicationHost.cs | 1 - Emby.Common.Implementations/Net/UdpSocket.cs | 69 ++-- Emby.Server.Core/ApplicationHost.cs | 3 - .../Emby.Server.Implementations.csproj | 1 + .../IO/AsyncStreamCopier.cs | 458 +++++++++++++++++++++ .../TunerHosts/HdHomerun/HdHomerunHttpStream.cs | 4 +- .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 1 + MediaBrowser.ServerApplication/WindowsAppHost.cs | 5 - SocketHttpListener/Net/HttpConnection.cs | 2 +- .../Net/HttpResponseStream.Managed.cs | 20 +- 10 files changed, 525 insertions(+), 39 deletions(-) create mode 100644 Emby.Server.Implementations/IO/AsyncStreamCopier.cs (limited to 'SocketHttpListener/Net') diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs index dd4be9aae..835088fea 100644 --- a/Emby.Common.Implementations/BaseApplicationHost.cs +++ b/Emby.Common.Implementations/BaseApplicationHost.cs @@ -438,7 +438,6 @@ namespace Emby.Common.Implementations var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName); assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, assemblyName.Version, assemblyId); - return null; } var isFirstRun = !File.Exists(plugin.ConfigurationFilePath); diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Common.Implementations/Net/UdpSocket.cs index 678cf6f03..5e110e464 100644 --- a/Emby.Common.Implementations/Net/UdpSocket.cs +++ b/Emby.Common.Implementations/Net/UdpSocket.cs @@ -116,8 +116,6 @@ namespace Emby.Common.Implementations.Net private set; } - private readonly AsyncCallback _defaultAsyncCallback = (i) => { }; - public IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback) { EndPoint receivedFromEndPoint = new IPEndPoint(IPAddress.Any, 0); @@ -145,9 +143,30 @@ namespace Emby.Common.Implementations.Net public Task ReceiveAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - var result = BeginReceive(buffer, offset, count, _defaultAsyncCallback); + var taskCompletion = new TaskCompletionSource(); + + Action callback = callbackResult => + { + try + { + taskCompletion.TrySetResult(EndReceive(callbackResult)); + } + catch (Exception ex) + { + taskCompletion.TrySetException(ex); + } + }; + + var result = BeginReceive(buffer, offset, count, new AsyncCallback(callback)); - return Task.Factory.FromAsync(result, EndReceive); + if (result.CompletedSynchronously) + { + callback(result); + } + + cancellationToken.Register(() => taskCompletion.TrySetCanceled()); + + return taskCompletion.Task; } public Task ReceiveAsync(CancellationToken cancellationToken) @@ -159,9 +178,30 @@ namespace Emby.Common.Implementations.Net public Task SendToAsync(byte[] buffer, int offset, int size, IpEndPointInfo endPoint, CancellationToken cancellationToken) { - var result = BeginSendTo(buffer, offset, size, endPoint, _defaultAsyncCallback, null); + var taskCompletion = new TaskCompletionSource(); + + Action callback = callbackResult => + { + try + { + taskCompletion.TrySetResult(EndSendTo(callbackResult)); + } + catch (Exception ex) + { + taskCompletion.TrySetException(ex); + } + }; - return Task.Factory.FromAsync(result, EndSendTo); + var result = BeginSendTo(buffer, offset, size, endPoint, new AsyncCallback(callback), null); + + if (result.CompletedSynchronously) + { + callback(result); + } + + cancellationToken.Register(() => taskCompletion.TrySetCanceled()); + + return taskCompletion.Task; } public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, IpEndPointInfo endPoint, AsyncCallback callback, object state) @@ -208,22 +248,5 @@ namespace Emby.Common.Implementations.Net return NetworkManager.ToIpEndPointInfo(endpoint); } - - private class AsyncReceiveState - { - public AsyncReceiveState(Socket socket, EndPoint remoteEndPoint) - { - this.Socket = socket; - this.RemoteEndPoint = remoteEndPoint; - } - - public EndPoint RemoteEndPoint; - public byte[] Buffer = new byte[8192]; - - public Socket Socket { get; private set; } - - public TaskCompletionSource TaskCompletionSource { get; set; } - - } } } diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 0fe30eb80..7a13334e4 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -1278,9 +1278,6 @@ namespace Emby.Server.Core // Emby.Server implementations list.Add(GetAssembly(typeof(InstallationManager))); - // Emby.Server.Core - list.Add(GetAssembly(typeof(ApplicationHost))); - // MediaEncoding list.Add(GetAssembly(typeof(MediaEncoder))); diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 3c58a55a9..20a0e708c 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -102,6 +102,7 @@ + diff --git a/Emby.Server.Implementations/IO/AsyncStreamCopier.cs b/Emby.Server.Implementations/IO/AsyncStreamCopier.cs new file mode 100644 index 000000000..e7330591c --- /dev/null +++ b/Emby.Server.Implementations/IO/AsyncStreamCopier.cs @@ -0,0 +1,458 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Emby.Server.Implementations.IO +{ + public class AsyncStreamCopier : IDisposable + { + // size in bytes of the buffers in the buffer pool + private const int DefaultBufferSize = 4096; + private readonly int _bufferSize; + // number of buffers in the pool + private const int DefaultBufferCount = 4; + private readonly int _bufferCount; + + // indexes of the next buffer to read into/write from + private int _nextReadBuffer = -1; + private int _nextWriteBuffer = -1; + + // the buffer pool, implemented as an array, and used in a cyclic way + private readonly byte[][] _buffers; + // sizes in bytes of the available (read) data in the buffers + private readonly int[] _sizes; + // the streams... + private Stream _source; + private Stream _target; + private readonly bool _closeStreamsOnEnd; + + // number of buffers that are ready to be written + private int _buffersToWrite; + // flag indicating that there is still a read operation to be scheduled + // (source end of stream not reached) + private volatile bool _moreDataToRead; + // the result of the whole operation, returned by BeginCopy() + private AsyncResult _asyncResult; + // any exception that occurs during an async operation + // stored here for rethrow + private Exception _exception; + + public TaskCompletionSource TaskCompletionSource; + private long _bytesToRead; + private long _totalBytesWritten; + private CancellationToken _cancellationToken; + + public AsyncStreamCopier(Stream source, + Stream target, + long bytesToRead, + CancellationToken cancellationToken, + bool closeStreamsOnEnd = false, + int bufferSize = DefaultBufferSize, + int bufferCount = DefaultBufferCount) + { + if (source == null) + throw new ArgumentNullException("source"); + if (target == null) + throw new ArgumentNullException("target"); + if (!source.CanRead) + throw new ArgumentException("Cannot copy from a non-readable stream."); + if (!target.CanWrite) + throw new ArgumentException("Cannot copy to a non-writable stream."); + _source = source; + _target = target; + _moreDataToRead = true; + _closeStreamsOnEnd = closeStreamsOnEnd; + _bufferSize = bufferSize; + _bufferCount = bufferCount; + _buffers = new byte[_bufferCount][]; + _sizes = new int[_bufferCount]; + _bytesToRead = bytesToRead; + _cancellationToken = cancellationToken; + } + + ~AsyncStreamCopier() + { + // ensure any exception cannot be ignored + ThrowExceptionIfNeeded(); + } + + public static Task CopyStream(Stream source, Stream target, int bufferSize, int bufferCount, CancellationToken cancellationToken) + { + return CopyStream(source, target, 0, bufferSize, bufferCount, cancellationToken); + } + + public static Task CopyStream(Stream source, Stream target, long size, int bufferSize, int bufferCount, CancellationToken cancellationToken) + { + var copier = new AsyncStreamCopier(source, target, size, cancellationToken, false, bufferSize, bufferCount); + var taskCompletion = new TaskCompletionSource(); + + copier.TaskCompletionSource = taskCompletion; + + var result = copier.BeginCopy(StreamCopyCallback, copier); + + if (result.CompletedSynchronously) + { + StreamCopyCallback(result); + } + + cancellationToken.Register(() => taskCompletion.TrySetCanceled()); + + return taskCompletion.Task; + } + + private static void StreamCopyCallback(IAsyncResult result) + { + var copier = (AsyncStreamCopier)result.AsyncState; + var taskCompletion = copier.TaskCompletionSource; + + try + { + copier.EndCopy(result); + taskCompletion.TrySetResult(true); + } + catch (Exception ex) + { + taskCompletion.TrySetException(ex); + } + } + + public void Dispose() + { + if (_asyncResult != null) + _asyncResult.Dispose(); + if (_closeStreamsOnEnd) + { + if (_source != null) + { + _source.Dispose(); + _source = null; + } + if (_target != null) + { + _target.Dispose(); + _target = null; + } + } + GC.SuppressFinalize(this); + ThrowExceptionIfNeeded(); + } + + public IAsyncResult BeginCopy(AsyncCallback callback, object state) + { + // avoid concurrent start of the copy on separate threads + if (Interlocked.CompareExchange(ref _asyncResult, new AsyncResult(callback, state), null) != null) + throw new InvalidOperationException("A copy operation has already been started on this object."); + // allocate buffers + for (int i = 0; i < _bufferCount; i++) + _buffers[i] = new byte[_bufferSize]; + + // we pass false to BeginRead() to avoid completing the async result + // immediately which would result in invoking the callback + // when the method fails synchronously + BeginRead(false); + // throw exception synchronously if there is one + ThrowExceptionIfNeeded(); + return _asyncResult; + } + + public void EndCopy(IAsyncResult ar) + { + if (ar != _asyncResult) + throw new InvalidOperationException("Invalid IAsyncResult object."); + + if (!_asyncResult.IsCompleted) + _asyncResult.AsyncWaitHandle.WaitOne(); + + if (_closeStreamsOnEnd) + { + _source.Close(); + _source = null; + _target.Close(); + _target = null; + } + + //_logger.Info("AsyncStreamCopier {0} bytes requested. {1} bytes transferred", _bytesToRead, _totalBytesWritten); + ThrowExceptionIfNeeded(); + } + + /// + /// Here we'll throw a pending exception if there is one, + /// and remove it from our instance, so we know it has been consumed. + /// + private void ThrowExceptionIfNeeded() + { + if (_exception != null) + { + var exception = _exception; + _exception = null; + throw exception; + } + } + + private void BeginRead(bool completeOnError = true) + { + if (!_moreDataToRead) + { + return; + } + if (_asyncResult.IsCompleted) + return; + int bufferIndex = Interlocked.Increment(ref _nextReadBuffer) % _bufferCount; + + try + { + _source.BeginRead(_buffers[bufferIndex], 0, _bufferSize, EndRead, bufferIndex); + } + catch (Exception exception) + { + _exception = exception; + if (completeOnError) + _asyncResult.Complete(false); + } + } + + private void BeginWrite() + { + if (_asyncResult.IsCompleted) + return; + // this method can actually be called concurrently!! + // indeed, let's say we call a BeginWrite, and the thread gets interrupted + // just after making the IO request. + // At that moment, the thread is still in the method. And then the IO request + // ends (extremely fast io, or caching...), EndWrite gets called + // on another thread, and calls BeginWrite again! There we have it! + // That is the reason why an Interlocked is needed here. + int bufferIndex = Interlocked.Increment(ref _nextWriteBuffer) % _bufferCount; + + try + { + int bytesToWrite; + if (_bytesToRead > 0) + { + var bytesLeftToWrite = _bytesToRead - _totalBytesWritten; + bytesToWrite = Convert.ToInt32(Math.Min(_sizes[bufferIndex], bytesLeftToWrite)); + } + else + { + bytesToWrite = _sizes[bufferIndex]; + } + + _target.BeginWrite(_buffers[bufferIndex], 0, bytesToWrite, EndWrite, null); + + _totalBytesWritten += bytesToWrite; + } + catch (Exception exception) + { + _exception = exception; + _asyncResult.Complete(false); + } + } + + private void EndRead(IAsyncResult ar) + { + try + { + int read = _source.EndRead(ar); + _moreDataToRead = read > 0; + var bufferIndex = (int)ar.AsyncState; + _sizes[bufferIndex] = read; + } + catch (Exception exception) + { + _exception = exception; + _asyncResult.Complete(false); + return; + } + + if (_moreDataToRead && !_cancellationToken.IsCancellationRequested) + { + int usedBuffers = Interlocked.Increment(ref _buffersToWrite); + // if we incremented from zero to one, then it means we just + // added the single buffer to write, so a writer could not + // be busy, and we have to schedule one. + if (usedBuffers == 1) + BeginWrite(); + // test if there is at least a free buffer, and schedule + // a read, as we have read some data + if (usedBuffers < _bufferCount) + BeginRead(); + } + else + { + // we did not add a buffer, because no data was read, and + // there is no buffer left to write so this is the end... + if (Thread.VolatileRead(ref _buffersToWrite) == 0) + { + _asyncResult.Complete(false); + } + } + } + + private void EndWrite(IAsyncResult ar) + { + try + { + _target.EndWrite(ar); + } + catch (Exception exception) + { + _exception = exception; + _asyncResult.Complete(false); + return; + } + + int buffersLeftToWrite = Interlocked.Decrement(ref _buffersToWrite); + // no reader could be active if all buffers were full of data waiting to be written + bool noReaderIsBusy = buffersLeftToWrite == _bufferCount - 1; + // note that it is possible that both a reader and + // a writer see the end of the copy and call Complete + // on the _asyncResult object. That race condition is handled by + // Complete that ensures it is only executed fully once. + + long bytesLeftToWrite; + if (_bytesToRead > 0) + { + bytesLeftToWrite = _bytesToRead - _totalBytesWritten; + } + else + { + bytesLeftToWrite = 1; + } + + if (!_moreDataToRead || bytesLeftToWrite <= 0 || _cancellationToken.IsCancellationRequested) + { + // at this point we know no reader can schedule a read or write + if (Thread.VolatileRead(ref _buffersToWrite) == 0) + { + // nothing left to write, so it is the end + _asyncResult.Complete(false); + return; + } + } + else + // here, we know we have something left to read, + // so schedule a read if no read is busy + if (noReaderIsBusy) + BeginRead(); + + // also schedule a write if we are sure we did not write the last buffer + // note that if buffersLeftToWrite is zero and a reader has put another + // buffer to write between the time we decremented _buffersToWrite + // and now, that reader will also schedule another write, + // as it will increment _buffersToWrite from zero to one + if (buffersLeftToWrite > 0) + BeginWrite(); + } + } + + internal class AsyncResult : IAsyncResult, IDisposable + { + // Fields set at construction which never change while + // operation is pending + private readonly AsyncCallback _asyncCallback; + private readonly object _asyncState; + + // Fields set at construction which do change after + // operation completes + private const int StatePending = 0; + private const int StateCompletedSynchronously = 1; + private const int StateCompletedAsynchronously = 2; + private int _completedState = StatePending; + + // Field that may or may not get set depending on usage + private ManualResetEvent _waitHandle; + + internal AsyncResult( + AsyncCallback asyncCallback, + object state) + { + _asyncCallback = asyncCallback; + _asyncState = state; + } + + internal bool Complete(bool completedSynchronously) + { + bool result = false; + + // The _completedState field MUST be set prior calling the callback + int prevState = Interlocked.CompareExchange(ref _completedState, + completedSynchronously ? StateCompletedSynchronously : + StateCompletedAsynchronously, StatePending); + if (prevState == StatePending) + { + // If the event exists, set it + if (_waitHandle != null) + _waitHandle.Set(); + + if (_asyncCallback != null) + _asyncCallback(this); + + result = true; + } + + return result; + } + + #region Implementation of IAsyncResult + + public Object AsyncState { get { return _asyncState; } } + + public bool CompletedSynchronously + { + get + { + return Thread.VolatileRead(ref _completedState) == + StateCompletedSynchronously; + } + } + + public WaitHandle AsyncWaitHandle + { + get + { + if (_waitHandle == null) + { + bool done = IsCompleted; + var mre = new ManualResetEvent(done); + if (Interlocked.CompareExchange(ref _waitHandle, + mre, null) != null) + { + // Another thread created this object's event; dispose + // the event we just created + mre.Close(); + } + else + { + if (!done && IsCompleted) + { + // If the operation wasn't done when we created + // the event but now it is done, set the event + _waitHandle.Set(); + } + } + } + return _waitHandle; + } + } + + public bool IsCompleted + { + get + { + return Thread.VolatileRead(ref _completedState) != + StatePending; + } + } + #endregion + + public void Dispose() + { + if (_waitHandle != null) + { + _waitHandle.Dispose(); + _waitHandle = null; + } + } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs index 477eef7ab..a81a1199e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs @@ -2,6 +2,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.IO; using MediaBrowser.Model.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -105,7 +106,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { ResolveAfterDelay(3000, openTaskCompletionSource); - await response.Content.CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false); + //await response.Content.CopyToAsync(fileStream, 81920, cancellationToken).ConfigureAwait(false); + await AsyncStreamCopier.CopyStream(response.Content, fileStream, 81920, 4, cancellationToken).ConfigureAwait(false); } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 97753b3d3..142805c37 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Implementations.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Library; diff --git a/MediaBrowser.ServerApplication/WindowsAppHost.cs b/MediaBrowser.ServerApplication/WindowsAppHost.cs index 537c8b323..7ef8e03f7 100644 --- a/MediaBrowser.ServerApplication/WindowsAppHost.cs +++ b/MediaBrowser.ServerApplication/WindowsAppHost.cs @@ -64,11 +64,6 @@ namespace MediaBrowser.ServerApplication { var list = new List(); - if (!Environment.Is64BitProcess) - { - //list.Add(typeof(PismoIsoManager).Assembly); - } - list.Add(typeof(DefaultIntroProvider).Assembly); list.Add(typeof(ConnectManager).Assembly); list.Add(typeof(SyncManager).Assembly); diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs index 627b671bf..eda633207 100644 --- a/SocketHttpListener/Net/HttpConnection.cs +++ b/SocketHttpListener/Net/HttpConnection.cs @@ -220,7 +220,7 @@ namespace SocketHttpListener.Net //o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment); - o_stream = new HttpResponseStream(stream, context.Response, false, _memoryStreamFactory, sock, supportsDirectSocketAccess, _environment, _fileSystem); + o_stream = new HttpResponseStream(stream, context.Response, false, _memoryStreamFactory, sock, supportsDirectSocketAccess, _environment, _fileSystem, _logger); } return o_stream; } diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs index 0a9efccb2..73c296580 100644 --- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs +++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; +using System.Net.Sockets; using System.Runtime.ExceptionServices; using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; using MediaBrowser.Model.System; @@ -54,7 +56,9 @@ namespace SocketHttpListener.Net private readonly bool _supportsDirectSocketAccess; private readonly IEnvironmentInfo _environment; private readonly IFileSystem _fileSystem; - internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, IAcceptSocket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem) + private readonly ILogger _logger; + + internal HttpResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, IAcceptSocket socket, bool supportsDirectSocketAccess, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger) { _response = response; _ignore_errors = ignore_errors; @@ -63,6 +67,7 @@ namespace SocketHttpListener.Net _supportsDirectSocketAccess = supportsDirectSocketAccess; _environment = environment; _fileSystem = fileSystem; + _logger = logger; _stream = stream; } @@ -173,7 +178,7 @@ namespace SocketHttpListener.Net { _stream.Write(buffer, offset, count); } - catch (IOException ex) + catch (Exception ex) { throw new HttpListenerException(ex.HResult, ex.Message); } @@ -265,7 +270,7 @@ namespace SocketHttpListener.Net { return _stream.BeginWrite(buffer, offset, size, cback, state); } - catch (IOException ex) + catch (Exception ex) { if (_ignore_errors) { @@ -305,12 +310,12 @@ namespace SocketHttpListener.Net if (_response.SendChunked) _stream.Write(s_crlf, 0, 2); } - catch (IOException ex) + catch (Exception ex) { // NetworkStream wraps exceptions in IOExceptions; if the underlying socket operation // failed because of invalid arguments or usage, propagate that error. Otherwise // wrap the whole thing in an HttpListenerException. This is all to match Windows behavior. - if (ex.InnerException is ArgumentException || ex.InnerException is InvalidOperationException) + if (ex.InnerException is ArgumentException || ex.InnerException is InvalidOperationException || ex.InnerException is SocketException) { throw ex.InnerException; } @@ -365,6 +370,11 @@ namespace SocketHttpListener.Net { var allowAsync = _environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; + //if (count <= 0) + //{ + // allowAsync = true; + //} + var fileOpenOptions = offset > 0 ? FileOpenOptions.RandomAccess : FileOpenOptions.SequentialScan; -- cgit v1.2.3 From 28988b056ccc8efad54905b6f10ff0b9532c7130 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 25 May 2017 09:00:14 -0400 Subject: update stream copying --- Emby.Common.Implementations/Net/NetAcceptSocket.cs | 33 +- Emby.Common.Implementations/Net/SocketFactory.cs | 85 +++++ Emby.Common.Implementations/Net/UdpSocket.cs | 7 +- Emby.Server.Core/HttpServerFactory.cs | 78 +---- .../IO/AsyncStreamCopier.cs | 19 +- .../TunerHosts/HdHomerun/HdHomerunHttpStream.cs | 38 +++ .../TunerHosts/HdHomerun/HdHomerunUdpStream.cs | 90 ++++- MediaBrowser.Controller/LiveTv/LiveStream.cs | 93 +---- MediaBrowser.Model/Net/ISocketFactory.cs | 4 + SocketHttpListener/Net/HttpConnection.cs | 377 ++++++++++----------- SocketHttpListener/Net/HttpListenerResponse.cs | 47 +++ .../Net/HttpResponseStream.Managed.cs | 5 +- 12 files changed, 469 insertions(+), 407 deletions(-) (limited to 'SocketHttpListener/Net') diff --git a/Emby.Common.Implementations/Net/NetAcceptSocket.cs b/Emby.Common.Implementations/Net/NetAcceptSocket.cs index 82e7e9b00..5f97fd854 100644 --- a/Emby.Common.Implementations/Net/NetAcceptSocket.cs +++ b/Emby.Common.Implementations/Net/NetAcceptSocket.cs @@ -97,7 +97,6 @@ namespace Emby.Common.Implementations.Net _acceptor.StartAccept(); } -#if NET46 public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken) { var options = TransmitFileOptions.UseDefaultWorkerThread; @@ -117,25 +116,23 @@ namespace Emby.Common.Implementations.Net var client = data.Item1; var path = data.Item2; var taskCompletion = data.Item3; - + // Complete sending the data to the remote device. - try { - client.EndSendFile(ar); - taskCompletion.TrySetResult(true); -} - catch(SocketException ex){ - _logger.Info("Socket.SendFile failed for {0}. error code {1}", path, ex.SocketErrorCode); - taskCompletion.TrySetException(ex); -}catch(Exception ex){ - taskCompletion.TrySetException(ex); -} - } -#else - public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken) - { - throw new NotImplementedException(); + try + { + client.EndSendFile(ar); + taskCompletion.TrySetResult(true); + } + catch (SocketException ex) + { + _logger.Info("Socket.SendFile failed for {0}. error code {1}", path, ex.SocketErrorCode); + taskCompletion.TrySetException(ex); + } + catch (Exception ex) + { + taskCompletion.TrySetException(ex); + } } -#endif public void Dispose() { diff --git a/Emby.Common.Implementations/Net/SocketFactory.cs b/Emby.Common.Implementations/Net/SocketFactory.cs index 3562a8644..0a1232a40 100644 --- a/Emby.Common.Implementations/Net/SocketFactory.cs +++ b/Emby.Common.Implementations/Net/SocketFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; @@ -208,5 +209,89 @@ namespace Emby.Common.Implementations.Net throw; } } + + public Stream CreateNetworkStream(ISocket socket, bool ownsSocket) + { + var netSocket = (UdpSocket)socket; + + return new SocketStream(netSocket.Socket, ownsSocket); + } } + + public class SocketStream : Stream + { + private readonly Socket _socket; + + public SocketStream(Socket socket, bool ownsSocket) + { + _socket = socket; + } + + public override void Flush() + { + } + + public override bool CanRead + { + get { return true; } + } + public override bool CanSeek + { + get { return false; } + } + public override bool CanWrite + { + get { return true; } + } + public override long Length + { + get { throw new NotImplementedException(); } + } + public override long Position + { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + public override void Write(byte[] buffer, int offset, int count) + { + _socket.Send(buffer, offset, count, SocketFlags.None); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return _socket.BeginSend(buffer, offset, count, SocketFlags.None, callback, state); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + _socket.EndSend(asyncResult); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _socket.Receive(buffer, offset, count, SocketFlags.None); + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return _socket.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state); + } + + public override int EndRead(IAsyncResult asyncResult) + { + return _socket.EndReceive(asyncResult); + } + } + } diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Common.Implementations/Net/UdpSocket.cs index 5e110e464..578610b4c 100644 --- a/Emby.Common.Implementations/Net/UdpSocket.cs +++ b/Emby.Common.Implementations/Net/UdpSocket.cs @@ -14,11 +14,16 @@ namespace Emby.Common.Implementations.Net // THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS // Be careful to check any changes compile and work for all platform projects it is shared in. - internal sealed class UdpSocket : DisposableManagedObjectBase, ISocket + public sealed class UdpSocket : DisposableManagedObjectBase, ISocket { private Socket _Socket; private int _LocalPort; + public Socket Socket + { + get { return _Socket; } + } + private readonly SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs() { SocketFlags = SocketFlags.None diff --git a/Emby.Server.Core/HttpServerFactory.cs b/Emby.Server.Core/HttpServerFactory.cs index c30355f7a..e16cbea0e 100644 --- a/Emby.Server.Core/HttpServerFactory.cs +++ b/Emby.Server.Core/HttpServerFactory.cs @@ -83,7 +83,7 @@ namespace Emby.Server.Core { var netSocket = (NetAcceptSocket)acceptSocket; - return new WritableNetworkStream(netSocket.Socket, ownsSocket); + return new SocketStream(netSocket.Socket, ownsSocket); } public Task AuthenticateSslStreamAsServer(Stream stream, ICertificate certificate) @@ -109,80 +109,4 @@ namespace Emby.Server.Core public X509Certificate X509Certificate { get; private set; } } - - public class WritableNetworkStream : Stream - { - private readonly Socket _socket; - - public WritableNetworkStream(Socket socket, bool ownsSocket) - { - _socket = socket; - } - - public override void Flush() - { - } - - public override bool CanRead - { - get { return true; } - } - public override bool CanSeek - { - get { return false; } - } - public override bool CanWrite - { - get { return true; } - } - public override long Length - { - get { throw new NotImplementedException(); } - } - public override long Position - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public override void Write(byte[] buffer, int offset, int count) - { - _socket.Send(buffer, offset, count, SocketFlags.None); - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - return _socket.BeginSend(buffer, offset, count, SocketFlags.None, callback, state); - } - - public override void EndWrite(IAsyncResult asyncResult) - { - _socket.EndSend(asyncResult); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return _socket.Receive(buffer, offset, count, SocketFlags.None); - } - - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - return _socket.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state); - } - - public override int EndRead(IAsyncResult asyncResult) - { - return _socket.EndReceive(asyncResult); - } - } } diff --git a/Emby.Server.Implementations/IO/AsyncStreamCopier.cs b/Emby.Server.Implementations/IO/AsyncStreamCopier.cs index e7330591c..9e5ce0604 100644 --- a/Emby.Server.Implementations/IO/AsyncStreamCopier.cs +++ b/Emby.Server.Implementations/IO/AsyncStreamCopier.cs @@ -8,7 +8,7 @@ namespace Emby.Server.Implementations.IO public class AsyncStreamCopier : IDisposable { // size in bytes of the buffers in the buffer pool - private const int DefaultBufferSize = 4096; + private const int DefaultBufferSize = 81920; private readonly int _bufferSize; // number of buffers in the pool private const int DefaultBufferCount = 4; @@ -38,15 +38,16 @@ namespace Emby.Server.Implementations.IO // stored here for rethrow private Exception _exception; - public TaskCompletionSource TaskCompletionSource; + public TaskCompletionSource TaskCompletionSource; private long _bytesToRead; private long _totalBytesWritten; private CancellationToken _cancellationToken; + public int IndividualReadOffset = 0; public AsyncStreamCopier(Stream source, Stream target, - long bytesToRead, - CancellationToken cancellationToken, + long bytesToRead, + CancellationToken cancellationToken, bool closeStreamsOnEnd = false, int bufferSize = DefaultBufferSize, int bufferCount = DefaultBufferCount) @@ -77,15 +78,15 @@ namespace Emby.Server.Implementations.IO ThrowExceptionIfNeeded(); } - public static Task CopyStream(Stream source, Stream target, int bufferSize, int bufferCount, CancellationToken cancellationToken) + public static Task CopyStream(Stream source, Stream target, int bufferSize, int bufferCount, CancellationToken cancellationToken) { return CopyStream(source, target, 0, bufferSize, bufferCount, cancellationToken); } - public static Task CopyStream(Stream source, Stream target, long size, int bufferSize, int bufferCount, CancellationToken cancellationToken) + public static Task CopyStream(Stream source, Stream target, long size, int bufferSize, int bufferCount, CancellationToken cancellationToken) { var copier = new AsyncStreamCopier(source, target, size, cancellationToken, false, bufferSize, bufferCount); - var taskCompletion = new TaskCompletionSource(); + var taskCompletion = new TaskCompletionSource(); copier.TaskCompletionSource = taskCompletion; @@ -109,7 +110,7 @@ namespace Emby.Server.Implementations.IO try { copier.EndCopy(result); - taskCompletion.TrySetResult(true); + taskCompletion.TrySetResult(copier._totalBytesWritten); } catch (Exception ex) { @@ -238,7 +239,7 @@ namespace Emby.Server.Implementations.IO bytesToWrite = _sizes[bufferIndex]; } - _target.BeginWrite(_buffers[bufferIndex], 0, bytesToWrite, EndWrite, null); + _target.BeginWrite(_buffers[bufferIndex], IndividualReadOffset, bytesToWrite - IndividualReadOffset, EndWrite, null); _totalBytesWritten += bytesToWrite; } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs index a81a1199e..5db842dec 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs @@ -149,5 +149,43 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { return CopyFileTo(_tempFilePath, false, stream, cancellationToken); } + + protected async Task CopyFileTo(string path, bool allowEndOfFile, Stream outputStream, CancellationToken cancellationToken) + { + var eofCount = 0; + + long startPosition = -25000; + if (startPosition < 0) + { + var length = FileSystem.GetFileInfo(path).Length; + startPosition = Math.Max(length - startPosition, 0); + } + + using (var inputStream = GetInputStream(path, startPosition, true)) + { + if (startPosition > 0) + { + inputStream.Position = startPosition; + } + + while (eofCount < 20 || !allowEndOfFile) + { + var bytesRead = await AsyncStreamCopier.CopyStream(inputStream, outputStream, 81920, 4, cancellationToken).ConfigureAwait(false); + + //var position = fs.Position; + //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); + + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + } + } + } + } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 142805c37..2989177c0 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -171,24 +171,92 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return CopyFileTo(_tempFilePath, false, stream, cancellationToken); } - private static int RtpHeaderBytes = 12; - private async Task CopyTo(ISocket udpClient, Stream outputStream, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) + protected async Task CopyFileTo(string path, bool allowEndOfFile, Stream outputStream, CancellationToken cancellationToken) { - var receiveBuffer = new byte[8192]; + var eofCount = 0; - while (true) + long startPosition = -25000; + if (startPosition < 0) { - var data = await udpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false); - var bytesRead = data.ReceivedBytes - RtpHeaderBytes; - - await outputStream.WriteAsync(data.Buffer, RtpHeaderBytes, bytesRead, cancellationToken).ConfigureAwait(false); + var length = FileSystem.GetFileInfo(path).Length; + startPosition = Math.Max(length - startPosition, 0); + } + + using (var inputStream = GetInputStream(path, startPosition, true)) + { + if (startPosition > 0) + { + inputStream.Position = startPosition; + } - if (openTaskCompletionSource != null) + while (eofCount < 20 || !allowEndOfFile) { - Resolve(openTaskCompletionSource); - openTaskCompletionSource = null; + var bytesRead = await AsyncStreamCopier.CopyStream(inputStream, outputStream, 81920, 4, cancellationToken).ConfigureAwait(false); + + //var position = fs.Position; + //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); + + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + } } } } + + private static int RtpHeaderBytes = 12; + private Task CopyTo(ISocket udpClient, Stream outputStream, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) + { + return CopyStream(_socketFactory.CreateNetworkStream(udpClient, false), outputStream, 81920, 4, openTaskCompletionSource, cancellationToken); + } + + private Task CopyStream(Stream source, Stream target, int bufferSize, int bufferCount, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) + { + var copier = new AsyncStreamCopier(source, target, 0, cancellationToken, false, bufferSize, bufferCount); + copier.IndividualReadOffset = RtpHeaderBytes; + + var taskCompletion = new TaskCompletionSource(); + + copier.TaskCompletionSource = taskCompletion; + + var result = copier.BeginCopy(StreamCopyCallback, copier); + + if (openTaskCompletionSource != null) + { + Resolve(openTaskCompletionSource); + openTaskCompletionSource = null; + } + + if (result.CompletedSynchronously) + { + StreamCopyCallback(result); + } + + cancellationToken.Register(() => taskCompletion.TrySetCanceled()); + + return taskCompletion.Task; + } + + private void StreamCopyCallback(IAsyncResult result) + { + var copier = (AsyncStreamCopier)result.AsyncState; + var taskCompletion = copier.TaskCompletionSource; + + try + { + copier.EndCopy(result); + taskCompletion.TrySetResult(0); + } + catch (Exception ex) + { + taskCompletion.TrySetException(ex); + } + } + } } \ No newline at end of file diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs index 48468d1a0..912fed23c 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Controller.LiveTv return Task.FromResult(true); } - private Stream GetInputStream(string path, long startPosition, bool allowAsyncFileRead) + protected Stream GetInputStream(string path, long startPosition, bool allowAsyncFileRead) { var fileOpenOptions = startPosition > 0 ? FileOpenOptions.RandomAccess @@ -85,96 +85,5 @@ namespace MediaBrowser.Controller.LiveTv await Task.Delay(500).ConfigureAwait(false); await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false); } - - protected async Task CopyFileTo(string path, bool allowEndOfFile, Stream outputStream, CancellationToken cancellationToken) - { - var eofCount = 0; - - long startPosition = -25000; - if (startPosition < 0) - { - var length = FileSystem.GetFileInfo(path).Length; - startPosition = Math.Max(length - startPosition, 0); - } - - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - var allowAsyncFileRead = Environment.OperatingSystem != OperatingSystem.Windows; - - using (var inputStream = GetInputStream(path, startPosition, allowAsyncFileRead)) - { - if (startPosition > 0) - { - inputStream.Position = startPosition; - } - - while (eofCount < 20 || !allowEndOfFile) - { - int bytesRead; - if (allowAsyncFileRead) - { - bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); - } - else - { - bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false); - } - - //var position = fs.Position; - //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - - if (bytesRead == 0) - { - eofCount++; - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } - else - { - eofCount = 0; - } - } - } - } - - private async Task CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken) - { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - int totalBytesRead = 0; - - while ((bytesRead = source.Read(array, 0, array.Length)) != 0) - { - var bytesToWrite = bytesRead; - - if (bytesToWrite > 0) - { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - - totalBytesRead += bytesRead; - } - } - - return totalBytesRead; - } - - private async Task CopyToInternalAsync(Stream source, Stream destination, CancellationToken cancellationToken) - { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - int totalBytesRead = 0; - - while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) - { - var bytesToWrite = bytesRead; - - if (bytesToWrite > 0) - { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - - totalBytesRead += bytesRead; - } - } - - return totalBytesRead; - } } } diff --git a/MediaBrowser.Model/Net/ISocketFactory.cs b/MediaBrowser.Model/Net/ISocketFactory.cs index e7dbf6cb1..bf2424660 100644 --- a/MediaBrowser.Model/Net/ISocketFactory.cs +++ b/MediaBrowser.Model/Net/ISocketFactory.cs @@ -1,4 +1,6 @@  +using System.IO; + namespace MediaBrowser.Model.Net { /// @@ -33,6 +35,8 @@ namespace MediaBrowser.Model.Net ISocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort); IAcceptSocket CreateSocket(IpAddressFamily family, SocketType socketType, ProtocolType protocolType, bool dualMode); + + Stream CreateNetworkStream(ISocket socket, bool ownsSocket); } public enum SocketType diff --git a/SocketHttpListener/Net/HttpConnection.cs b/SocketHttpListener/Net/HttpConnection.cs index eda633207..9c87ff076 100644 --- a/SocketHttpListener/Net/HttpConnection.cs +++ b/SocketHttpListener/Net/HttpConnection.cs @@ -14,24 +14,25 @@ namespace SocketHttpListener.Net { sealed class HttpConnection { + private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead); const int BufferSize = 8192; - IAcceptSocket sock; - Stream stream; - EndPointListener epl; - MemoryStream ms; - byte[] buffer; - HttpListenerContext context; - StringBuilder current_line; - ListenerPrefix prefix; - HttpRequestStream i_stream; - Stream o_stream; - bool chunked; - int reuses; - bool context_bound; + IAcceptSocket _socket; + Stream _stream; + EndPointListener _epl; + MemoryStream _memoryStream; + byte[] _buffer; + HttpListenerContext _context; + StringBuilder _currentLine; + ListenerPrefix _prefix; + HttpRequestStream _requestStream; + Stream _responseStream; + bool _chunked; + int _reuses; + bool _contextBound; bool secure; - int s_timeout = 300000; // 90k ms for first request, 15k ms from then on + int _timeout = 300000; // 90k ms for first request, 15k ms from then on IpEndPointInfo local_ep; - HttpListener last_listener; + HttpListener _lastListener; int[] client_cert_errors; ICertificate cert; Stream ssl_stream; @@ -44,11 +45,11 @@ namespace SocketHttpListener.Net private readonly IFileSystem _fileSystem; private readonly IEnvironmentInfo _environment; - private HttpConnection(ILogger logger, IAcceptSocket sock, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) + private HttpConnection(ILogger logger, IAcceptSocket socket, EndPointListener epl, bool secure, ICertificate cert, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding, IFileSystem fileSystem, IEnvironmentInfo environment) { _logger = logger; - this.sock = sock; - this.epl = epl; + this._socket = socket; + this._epl = epl; this.secure = secure; this.cert = cert; _cryptoProvider = cryptoProvider; @@ -63,11 +64,11 @@ namespace SocketHttpListener.Net { if (secure == false) { - stream = _streamFactory.CreateNetworkStream(sock, false); + _stream = _streamFactory.CreateNetworkStream(_socket, false); } else { - //ssl_stream = epl.Listener.CreateSslStream(new NetworkStream(sock, false), false, (t, c, ch, e) => + //ssl_stream = _epl.Listener.CreateSslStream(new NetworkStream(_socket, false), false, (t, c, ch, e) => //{ // if (c == null) // return true; @@ -78,11 +79,11 @@ namespace SocketHttpListener.Net // client_cert_errors = new int[] { (int)e }; // return true; //}); - //stream = ssl_stream.AuthenticatedStream; + //_stream = ssl_stream.AuthenticatedStream; - ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(sock, false), false); + ssl_stream = _streamFactory.CreateSslStream(_streamFactory.CreateNetworkStream(_socket, false), false); await _streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert).ConfigureAwait(false); - stream = ssl_stream; + _stream = ssl_stream; } Init(); } @@ -100,7 +101,7 @@ namespace SocketHttpListener.Net { get { - return stream; + return _stream; } } @@ -111,32 +112,26 @@ namespace SocketHttpListener.Net void Init() { - if (ssl_stream != null) - { - //ssl_stream.AuthenticateAsServer(client_cert, true, (SslProtocols)ServicePointManager.SecurityProtocol, false); - //_streamFactory.AuthenticateSslStreamAsServer(ssl_stream, cert); - } - - context_bound = false; - i_stream = null; - o_stream = null; - prefix = null; - chunked = false; - ms = _memoryStreamFactory.CreateNew(); - position = 0; - input_state = InputState.RequestLine; - line_state = LineState.None; - context = new HttpListenerContext(this, _logger, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem); + _contextBound = false; + _requestStream = null; + _responseStream = null; + _prefix = null; + _chunked = false; + _memoryStream = new MemoryStream(); + _position = 0; + _inputState = InputState.RequestLine; + _lineState = LineState.None; + _context = new HttpListenerContext(this, _logger, _cryptoProvider, _memoryStreamFactory, _textEncoding, _fileSystem); } public bool IsClosed { - get { return (sock == null); } + get { return (_socket == null); } } public int Reuses { - get { return reuses; } + get { return _reuses; } } public IpEndPointInfo LocalEndPoint @@ -146,14 +141,14 @@ namespace SocketHttpListener.Net if (local_ep != null) return local_ep; - local_ep = (IpEndPointInfo)sock.LocalEndPoint; + local_ep = (IpEndPointInfo)_socket.LocalEndPoint; return local_ep; } } public IpEndPointInfo RemoteEndPoint { - get { return (IpEndPointInfo)sock.RemoteEndPoint; } + get { return (IpEndPointInfo)_socket.RemoteEndPoint; } } public bool IsSecure @@ -163,187 +158,186 @@ namespace SocketHttpListener.Net public ListenerPrefix Prefix { - get { return prefix; } - set { prefix = value; } + get { return _prefix; } + set { _prefix = value; } } - public async Task BeginReadRequest() + public void BeginReadRequest() { - if (buffer == null) - buffer = new byte[BufferSize]; - + if (_buffer == null) + _buffer = new byte[BufferSize]; try { - //if (reuses == 1) - // s_timeout = 15000; - var nRead = await stream.ReadAsync(buffer, 0, BufferSize).ConfigureAwait(false); - - OnReadInternal(nRead); + if (_reuses == 1) + _timeout = 15000; + //_timer.Change(_timeout, Timeout.Infinite); + _stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this); } - catch (Exception ex) + catch { - OnReadInternalException(ms, ex); + //_timer.Change(Timeout.Infinite, Timeout.Infinite); + CloseSocket(); + Unbind(); } } public HttpRequestStream GetRequestStream(bool chunked, long contentlength) { - if (i_stream == null) + if (_requestStream == null) { - byte[] buffer; - _memoryStreamFactory.TryGetBuffer(ms, out buffer); - - int length = (int)ms.Length; - ms = null; + byte[] buffer = _memoryStream.GetBuffer(); + int length = (int)_memoryStream.Length; + _memoryStream = null; if (chunked) { - this.chunked = true; - //context.Response.SendChunked = true; - i_stream = new ChunkedInputStream(context, stream, buffer, position, length - position); + _chunked = true; + //_context.Response.SendChunked = true; + _requestStream = new ChunkedInputStream(_context, _stream, buffer, _position, length - _position); } else { - i_stream = new HttpRequestStream(stream, buffer, position, length - position, contentlength); + _requestStream = new HttpRequestStream(_stream, buffer, _position, length - _position, contentlength); } } - return i_stream; + return _requestStream; } public Stream GetResponseStream(bool isExpect100Continue = false) { - // TODO: can we get this stream before reading the input? - if (o_stream == null) + // TODO: can we get this _stream before reading the input? + if (_responseStream == null) { - //context.Response.DetermineIfChunked(); - - var supportsDirectSocketAccess = !context.Response.SendChunked && !isExpect100Continue && !secure; + var supportsDirectSocketAccess = !_context.Response.SendChunked && !isExpect100Continue && !secure; - //o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding, _fileSystem, sock, supportsDirectSocketAccess, _logger, _environment); - - o_stream = new HttpResponseStream(stream, context.Response, false, _memoryStreamFactory, sock, supportsDirectSocketAccess, _environment, _fileSystem, _logger); + _responseStream = new HttpResponseStream(_stream, _context.Response, false, _memoryStreamFactory, _socket, supportsDirectSocketAccess, _environment, _fileSystem, _logger); } - return o_stream; + return _responseStream; } - void OnReadInternal(int nread) + private static void OnRead(IAsyncResult ares) { - ms.Write(buffer, 0, nread); - if (ms.Length > 32768) + HttpConnection cnc = (HttpConnection)ares.AsyncState; + cnc.OnReadInternal(ares); + } + + private void OnReadInternal(IAsyncResult ares) + { + //_timer.Change(Timeout.Infinite, Timeout.Infinite); + int nread = -1; + try + { + nread = _stream.EndRead(ares); + _memoryStream.Write(_buffer, 0, nread); + if (_memoryStream.Length > 32768) + { + SendError("Bad Request", 400); + Close(true); + return; + } + } + catch { - SendError("Bad request", 400); - Close(true); + if (_memoryStream != null && _memoryStream.Length > 0) + SendError(); + if (_socket != null) + { + CloseSocket(); + Unbind(); + } return; } if (nread == 0) { - //if (ms.Length > 0) - // SendError (); // Why bother? CloseSocket(); Unbind(); return; } - if (ProcessInput(ms)) + if (ProcessInput(_memoryStream)) { - if (!context.HaveError) - context.Request.FinishInitialization(); + if (!_context.HaveError) + _context.Request.FinishInitialization(); - if (context.HaveError) + if (_context.HaveError) { SendError(); Close(true); return; } - if (!epl.BindContext(context)) + if (!_epl.BindContext(_context)) { SendError("Invalid host", 400); Close(true); return; } - HttpListener listener = epl.Listener; - if (last_listener != listener) + HttpListener listener = _epl.Listener; + if (_lastListener != listener) { RemoveConnection(); listener.AddConnection(this); - last_listener = listener; + _lastListener = listener; } - context_bound = true; - listener.RegisterContext(context); + _contextBound = true; + listener.RegisterContext(_context); return; } - - BeginReadRequest(); - } - - private void OnReadInternalException(MemoryStream ms, Exception ex) - { - //_logger.ErrorException("Error in HttpConnection.OnReadInternal", ex); - - if (ms != null && ms.Length > 0) - SendError(); - if (sock != null) - { - CloseSocket(); - Unbind(); - } + _stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this); } - void RemoveConnection() + private void RemoveConnection() { - if (last_listener == null) - epl.RemoveConnection(this); + if (_lastListener == null) + _epl.RemoveConnection(this); else - last_listener.RemoveConnection(this); + _lastListener.RemoveConnection(this); } - enum InputState + private enum InputState { RequestLine, Headers } - enum LineState + private enum LineState { None, CR, LF } - InputState input_state = InputState.RequestLine; - LineState line_state = LineState.None; - int position; + InputState _inputState = InputState.RequestLine; + LineState _lineState = LineState.None; + int _position; // true -> done processing // false -> need more input - bool ProcessInput(MemoryStream ms) + private bool ProcessInput(MemoryStream ms) { - byte[] buffer; - _memoryStreamFactory.TryGetBuffer(ms, out buffer); - + byte[] buffer = ms.GetBuffer(); int len = (int)ms.Length; int used = 0; string line; while (true) { - if (context.HaveError) + if (_context.HaveError) return true; - if (position >= len) + if (_position >= len) break; try { - line = ReadLine(buffer, position, len - position, ref used); - position += used; + line = ReadLine(buffer, _position, len - _position, ref used); + _position += used; } catch { - context.ErrorMessage = "Bad request"; - context.ErrorStatus = 400; + _context.ErrorMessage = "Bad request"; + _context.ErrorStatus = 400; return true; } @@ -352,28 +346,28 @@ namespace SocketHttpListener.Net if (line == "") { - if (input_state == InputState.RequestLine) + if (_inputState == InputState.RequestLine) continue; - current_line = null; + _currentLine = null; ms = null; return true; } - if (input_state == InputState.RequestLine) + if (_inputState == InputState.RequestLine) { - context.Request.SetRequestLine(line); - input_state = InputState.Headers; + _context.Request.SetRequestLine(line); + _inputState = InputState.Headers; } else { try { - context.Request.AddHeader(line); + _context.Request.AddHeader(line); } catch (Exception e) { - context.ErrorMessage = e.Message; - context.ErrorStatus = 400; + _context.ErrorMessage = e.Message; + _context.ErrorStatus = 400; return true; } } @@ -382,42 +376,41 @@ namespace SocketHttpListener.Net if (used == len) { ms.SetLength(0); - position = 0; + _position = 0; } return false; } - string ReadLine(byte[] buffer, int offset, int len, ref int used) + private string ReadLine(byte[] buffer, int offset, int len, ref int used) { - if (current_line == null) - current_line = new StringBuilder(128); + if (_currentLine == null) + _currentLine = new StringBuilder(128); int last = offset + len; used = 0; - - for (int i = offset; i < last && line_state != LineState.LF; i++) + for (int i = offset; i < last && _lineState != LineState.LF; i++) { used++; byte b = buffer[i]; if (b == 13) { - line_state = LineState.CR; + _lineState = LineState.CR; } else if (b == 10) { - line_state = LineState.LF; + _lineState = LineState.LF; } else { - current_line.Append((char)b); + _currentLine.Append((char)b); } } string result = null; - if (line_state == LineState.LF) + if (_lineState == LineState.LF) { - line_state = LineState.None; - result = current_line.ToString(); - current_line.Length = 0; + _lineState = LineState.None; + result = _currentLine.ToString(); + _currentLine.Length = 0; } return result; @@ -427,20 +420,18 @@ namespace SocketHttpListener.Net { try { - HttpListenerResponse response = context.Response; + HttpListenerResponse response = _context.Response; response.StatusCode = status; response.ContentType = "text/html"; string description = HttpListenerResponse.GetStatusDescription(status); string str; if (msg != null) - str = String.Format("

{0} ({1})

", description, msg); + str = string.Format("

{0} ({1})

", description, msg); else - str = String.Format("

{0}

", description); + str = string.Format("

{0}

", description); - byte[] error = context.Response.ContentEncoding.GetBytes(str); - response.ContentLength64 = error.Length; - response.OutputStream.Write(error, 0, (int)error.Length); - response.Close(); + byte[] error = Encoding.Default.GetBytes(str); + response.Close(error, false); } catch { @@ -450,15 +441,15 @@ namespace SocketHttpListener.Net public void SendError() { - SendError(context.ErrorMessage, context.ErrorStatus); + SendError(_context.ErrorMessage, _context.ErrorStatus); } - void Unbind() + private void Unbind() { - if (context_bound) + if (_contextBound) { - epl.UnbindContext(context); - context_bound = false; + _epl.UnbindContext(_context); + _contextBound = false; } } @@ -469,64 +460,60 @@ namespace SocketHttpListener.Net private void CloseSocket() { - if (sock == null) + if (_socket == null) return; try { - sock.Close(); - } - catch - { + _socket.Close(); } + catch { } finally { - sock = null; + _socket = null; } + RemoveConnection(); } - internal void Close(bool force_close) + internal void Close(bool force) { - if (sock != null) + if (_socket != null) { - if (!context.Request.IsWebSocketRequest || force_close) - { - Stream st = GetResponseStream(); - if (st != null) - { - st.Dispose(); - } + Stream st = GetResponseStream(); + if (st != null) + st.Close(); - o_stream = null; - } + _responseStream = null; } - if (sock != null) + if (_socket != null) { - force_close |= !context.Request.KeepAlive; - if (!force_close) - force_close = (string.Equals(context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase)); - /* - if (!force_close) { -// bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 || -// status_code == 413 || status_code == 414 || status_code == 500 || -// status_code == 503); - force_close |= (context.Request.ProtocolVersion <= HttpVersion.Version10); - } - */ - - if (!force_close && context.Request.FlushInput()) + force |= !_context.Request.KeepAlive; + if (!force) + force = (string.Equals(_context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase)); + + if (!force && _context.Request.FlushInput()) { - reuses++; + if (_chunked && _context.Response.ForceCloseChunked == false) + { + // Don't close. Keep working. + _reuses++; + Unbind(); + Init(); + BeginReadRequest(); + return; + } + + _reuses++; Unbind(); Init(); BeginReadRequest(); return; } - IAcceptSocket s = sock; - sock = null; + IAcceptSocket s = _socket; + _socket = null; try { if (s != null) diff --git a/SocketHttpListener/Net/HttpListenerResponse.cs b/SocketHttpListener/Net/HttpListenerResponse.cs index 185454ef6..da7aff081 100644 --- a/SocketHttpListener/Net/HttpListenerResponse.cs +++ b/SocketHttpListener/Net/HttpListenerResponse.cs @@ -53,6 +53,11 @@ namespace SocketHttpListener.Net } } + public bool ForceCloseChunked + { + get { return false; } + } + public Encoding ContentEncoding { get @@ -335,6 +340,48 @@ namespace SocketHttpListener.Net context.Connection.Close(force); } + public void Close(byte[] responseEntity, bool willBlock) + { + //CheckDisposed(); + + if (responseEntity == null) + { + throw new ArgumentNullException(nameof(responseEntity)); + } + + //if (_boundaryType != BoundaryType.Chunked) + { + ContentLength64 = responseEntity.Length; + } + + if (willBlock) + { + try + { + OutputStream.Write(responseEntity, 0, responseEntity.Length); + } + finally + { + Close(false); + } + } + else + { + OutputStream.BeginWrite(responseEntity, 0, responseEntity.Length, iar => + { + var thisRef = (HttpListenerResponse)iar.AsyncState; + try + { + thisRef.OutputStream.EndWrite(iar); + } + finally + { + thisRef.Close(false); + } + }, this); + } + } + public void Close() { if (disposed) diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs index 73c296580..d6bb2c04a 100644 --- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs +++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs @@ -325,10 +325,7 @@ namespace SocketHttpListener.Net } } - private bool EnableSendFileWithSocket - { - get { return false; } - } + private bool EnableSendFileWithSocket = false; public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) { -- cgit v1.2.3 From 33014f77aaacb91cfbd820052f1a49af66a214e3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 26 May 2017 02:48:54 -0400 Subject: update GetItems method --- Emby.Common.Implementations/BaseApplicationHost.cs | 1 - .../Diagnostics/CommonProcess.cs | 5 + .../Emby.Common.Implementations.csproj | 1 + .../HttpClientManager/HttpClientManager.cs | 2 +- Emby.Common.Implementations/IO/ProgressStream.cs | 240 +++++++++++++++++++++ Emby.Common.Implementations/Net/NetAcceptSocket.cs | 12 ++ .../Serialization/XmlSerializer.cs | 1 - Emby.Dlna/ContentDirectory/ControlHandler.cs | 36 ++-- Emby.Dlna/Didl/DidlBuilder.cs | 19 +- Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs | 2 +- Emby.Drawing.ImageMagick/StripCollageBuilder.cs | 2 +- Emby.Drawing.ImageMagick/UnplayedCountIndicator.cs | 2 - Emby.Drawing.Skia/PlayedIndicatorDrawer.cs | 2 +- Emby.Drawing.Skia/UnplayedCountIndicator.cs | 2 +- Emby.Drawing/Common/ImageHeader.cs | 2 +- Emby.Drawing/ImageProcessor.cs | 2 +- Emby.Server.Core/ApplicationHost.cs | 4 +- .../Channels/ChannelManager.cs | 12 +- .../Collections/CollectionImageProvider.cs | 6 +- .../Collections/CollectionsDynamicFolder.cs | 2 +- .../Devices/CameraUploadsDynamicFolder.cs | 2 +- .../Devices/DeviceManager.cs | 1 - Emby.Server.Implementations/Dto/DtoService.cs | 18 +- .../EntryPoints/UserDataChangeNotifier.cs | 2 +- .../FileOrganization/EpisodeFileOrganizer.cs | 1 - .../FileOrganization/FileOrganizationService.cs | 2 +- .../FileOrganization/OrganizerScheduledTask.cs | 2 +- .../FileOrganization/TvFolderOrganizer.cs | 2 +- .../SocketSharp/WebSocketSharpListener.cs | 9 +- .../HttpServer/StreamWriter.cs | 2 +- Emby.Server.Implementations/IO/FileRefresher.cs | 2 +- .../IO/MbLinkShortcutHandler.cs | 2 +- .../Images/BaseDynamicImageProvider.cs | 33 +-- .../Library/CoreResolutionIgnoreRule.cs | 2 +- .../Library/LibraryManager.cs | 2 +- .../Library/ResolverHelper.cs | 2 - .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 2 +- .../Library/Resolvers/Audio/MusicArtistResolver.cs | 2 +- .../Library/Resolvers/Movies/MovieResolver.cs | 2 +- .../Library/Resolvers/SpecialFolderResolver.cs | 2 +- .../Library/Resolvers/TV/SeriesResolver.cs | 2 +- .../Library/UserDataManager.cs | 8 +- .../Library/Validators/PeopleValidator.cs | 2 +- .../LiveTv/EmbyTV/DirectRecorder.cs | 2 +- .../LiveTv/EmbyTV/EmbyTV.cs | 8 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../LiveTv/EmbyTV/ItemDataProvider.cs | 2 +- .../LiveTv/EmbyTV/SeriesTimerManager.cs | 2 - .../LiveTv/EmbyTV/TimerManager.cs | 2 +- .../LiveTv/LiveTvManager.cs | 2 +- .../TunerHosts/HdHomerun/HdHomerunManager.cs | 5 +- .../LiveTv/TunerHosts/M3UTunerHost.cs | 2 +- .../LiveTv/TunerHosts/M3uParser.cs | 1 - .../MediaEncoder/EncodingManager.cs | 2 +- .../Migrations/GuideMigration.cs | 4 +- .../Migrations/LibraryScanMigration.cs | 4 +- .../Photos/PhotoAlbumImageProvider.cs | 4 +- .../Playlists/PlaylistImageProvider.cs | 14 +- .../Playlists/PlaylistManager.cs | 8 +- .../ScheduledTasks/ChapterImagesTask.cs | 1 - .../ScheduledTasks/RefreshIntrosTask.cs | 2 +- .../ServerManager/ServerManager.cs | 2 +- .../ServerManager/WebSocketConnection.cs | 1 - .../Services/ResponseHelper.cs | 4 +- .../Services/ServiceController.cs | 6 +- .../Services/ServiceHandler.cs | 3 +- .../Session/SessionManager.cs | 8 +- .../Session/SessionWebSocketListener.cs | 23 -- .../UserViews/CollectionFolderImageProvider.cs | 9 +- .../UserViews/DynamicImageProvider.cs | 9 +- MediaBrowser.Api/ApiEntryPoint.cs | 4 +- MediaBrowser.Api/ConfigurationService.cs | 5 +- MediaBrowser.Api/Dlna/DlnaServerService.cs | 2 +- MediaBrowser.Api/FilterService.cs | 4 +- MediaBrowser.Api/Images/ImageByNameService.cs | 2 - MediaBrowser.Api/Images/ImageService.cs | 2 +- MediaBrowser.Api/Images/RemoteImageService.cs | 7 +- MediaBrowser.Api/ItemRefreshService.cs | 2 +- MediaBrowser.Api/Library/LibraryService.cs | 2 +- .../Library/LibraryStructureService.cs | 2 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 2 +- MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs | 2 +- .../Playback/Progressive/AudioService.cs | 2 - .../Progressive/ProgressiveStreamWriter.cs | 2 +- MediaBrowser.Api/Reports/ReportsService.cs | 24 +-- MediaBrowser.Api/Subtitles/SubtitleService.cs | 2 +- MediaBrowser.Api/System/SystemService.cs | 2 +- MediaBrowser.Api/TvShowsService.cs | 4 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 8 +- MediaBrowser.Api/UserLibrary/PlaystateService.cs | 2 +- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 5 +- MediaBrowser.Api/UserLibrary/UserViewsService.cs | 2 +- MediaBrowser.Api/VideosService.cs | 2 +- MediaBrowser.Common/IO/ProgressStream.cs | 210 ------------------ MediaBrowser.Common/MediaBrowser.Common.csproj | 2 +- MediaBrowser.Controller/Channels/Channel.cs | 6 +- .../Channels/IChannelManager.cs | 2 +- .../Entities/AggregateFolder.cs | 1 - MediaBrowser.Controller/Entities/Audio/Audio.cs | 2 +- MediaBrowser.Controller/Entities/BaseItem.cs | 6 +- .../Entities/CollectionFolder.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 30 +-- MediaBrowser.Controller/Entities/IHasImages.cs | 2 +- MediaBrowser.Controller/Entities/IHasUserData.cs | 2 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 2 +- MediaBrowser.Controller/Entities/TV/Season.cs | 4 +- MediaBrowser.Controller/Entities/TV/Series.cs | 6 +- MediaBrowser.Controller/Entities/UserRootFolder.cs | 8 +- MediaBrowser.Controller/Entities/UserView.cs | 8 +- .../Entities/UserViewBuilder.cs | 15 +- MediaBrowser.Controller/Entities/Video.cs | 4 +- MediaBrowser.Controller/IO/FileData.cs | 2 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 2 +- .../Library/IUserDataManager.cs | 4 +- MediaBrowser.Controller/Library/ItemResolveArgs.cs | 2 +- .../MediaEncoding/IMediaEncoder.cs | 2 +- .../MediaEncoding/MediaEncoderHelpers.cs | 2 +- MediaBrowser.Controller/Net/IHttpResultFactory.cs | 2 +- MediaBrowser.Controller/Net/StaticResultOptions.cs | 2 +- MediaBrowser.Controller/Playlists/Playlist.cs | 14 +- .../Providers/DirectoryService.cs | 2 +- .../Providers/IDirectoryService.cs | 2 +- .../Providers/LocalImageInfo.cs | 2 +- .../Providers/MetadataRefreshOptions.cs | 2 +- MediaBrowser.Controller/Resolvers/IItemResolver.cs | 2 +- .../Resolvers/IResolverIgnoreRule.cs | 2 +- MediaBrowser.LocalMetadata/BaseXmlProvider.cs | 2 +- .../Images/CollectionFolderImageProvider.cs | 2 +- .../Images/EpisodeLocalImageProvider.cs | 2 +- .../Images/ImagesByNameImageProvider.cs | 2 +- .../Images/InternalMetadataFolderImageProvider.cs | 2 +- .../Images/LocalImageProvider.cs | 2 +- .../Parsers/EpisodeXmlParser.cs | 2 +- .../Providers/BoxSetXmlProvider.cs | 2 +- .../Providers/EpisodeXmlProvider.cs | 2 +- .../Providers/FolderXmlProvider.cs | 2 +- .../Providers/GameSystemXmlProvider.cs | 2 +- .../Providers/GameXmlProvider.cs | 2 +- .../Providers/MovieXmlProvider.cs | 2 +- .../Providers/MusicVideoXmlProvider.cs | 2 +- .../Providers/PlaylistXmlProvider.cs | 2 +- .../Providers/SeriesXmlProvider.cs | 2 +- .../Providers/VideoXmlProvider.cs | 2 +- .../Savers/BoxSetXmlSaver.cs | 2 +- .../Savers/FolderXmlSaver.cs | 2 - .../Configuration/EncodingConfigurationFactory.cs | 2 +- .../Encoder/FontConfigLoader.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 6 +- .../Probing/ProbeResultNormalizer.cs | 2 +- .../Subtitles/SubtitleEncoder.cs | 8 +- MediaBrowser.Model/Diagnostics/IProcess.cs | 2 + MediaBrowser.Model/Net/IAcceptSocket.cs | 5 +- MediaBrowser.Model/Net/ISocket.cs | 5 - .../Books/AudioBookMetadataService.cs | 2 +- .../Books/AudioPodcastMetadataService.cs | 2 +- .../Books/BookMetadataService.cs | 2 +- .../BoxSets/BoxSetMetadataService.cs | 6 +- .../BoxSets/MovieDbBoxSetProvider.cs | 2 +- .../Channels/ChannelMetadataService.cs | 2 +- .../Folders/CollectionFolderMetadataService.cs | 2 +- .../Folders/FolderMetadataService.cs | 2 +- .../Folders/UserViewMetadataService.cs | 2 +- .../GameGenres/GameGenreMetadataService.cs | 2 +- .../Games/GameMetadataService.cs | 2 +- .../Games/GameSystemMetadataService.cs | 2 +- .../Genres/GenreMetadataService.cs | 2 +- .../LiveTv/AudioRecordingService.cs | 2 +- .../LiveTv/ChannelMetadataService.cs | 2 +- .../LiveTv/ProgramMetadataService.cs | 2 +- .../LiveTv/VideoRecordingService.cs | 2 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 2 +- .../Manager/ItemImageProvider.cs | 2 +- MediaBrowser.Providers/Manager/MetadataService.cs | 10 +- MediaBrowser.Providers/Manager/ProviderManager.cs | 11 +- .../MediaInfo/FFProbeVideoInfo.cs | 2 +- .../Movies/FanartMovieImageProvider.cs | 2 +- .../Movies/GenericMovieDbInfo.cs | 2 +- MediaBrowser.Providers/Movies/MovieDbProvider.cs | 2 +- .../Movies/MovieMetadataService.cs | 2 +- .../Music/AlbumMetadataService.cs | 5 +- .../Music/ArtistMetadataService.cs | 6 +- .../Music/AudioDbAlbumProvider.cs | 6 +- .../Music/AudioDbArtistProvider.cs | 6 +- .../Music/AudioMetadataService.cs | 2 - .../Music/FanArtAlbumProvider.cs | 2 +- .../Music/FanArtArtistProvider.cs | 2 +- .../Music/MovieDbMusicVideoProvider.cs | 4 +- .../Music/MusicVideoMetadataService.cs | 2 +- .../MusicGenres/MusicGenreMetadataService.cs | 2 +- MediaBrowser.Providers/Omdb/OmdbImageProvider.cs | 2 +- MediaBrowser.Providers/Omdb/OmdbItemProvider.cs | 2 +- MediaBrowser.Providers/Omdb/OmdbProvider.cs | 6 +- .../People/MovieDbPersonProvider.cs | 2 +- .../People/PersonMetadataService.cs | 2 +- .../Photos/PhotoAlbumMetadataService.cs | 2 +- .../Photos/PhotoMetadataService.cs | 2 - .../Playlists/PlaylistMetadataService.cs | 2 +- .../Studios/StudioMetadataService.cs | 2 - .../Subtitles/SubtitleManager.cs | 2 +- MediaBrowser.Providers/TV/DummySeasonProvider.cs | 2 +- .../TV/EpisodeMetadataService.cs | 6 +- .../TV/FanArt/FanArtSeasonProvider.cs | 2 +- .../TV/FanArt/FanartSeriesProvider.cs | 2 +- .../TV/MissingEpisodeProvider.cs | 2 +- .../TV/Omdb/OmdbEpisodeProvider.cs | 2 +- MediaBrowser.Providers/TV/SeasonMetadataService.cs | 6 +- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 2 +- .../TV/TheMovieDb/MovieDbEpisodeImageProvider.cs | 2 +- .../TV/TheMovieDb/MovieDbEpisodeProvider.cs | 2 +- .../TV/TheMovieDb/MovieDbProviderBase.cs | 2 +- .../TV/TheMovieDb/MovieDbSeasonProvider.cs | 2 +- .../TV/TheMovieDb/MovieDbSeriesProvider.cs | 2 +- .../TV/TheTVDB/TvdbEpisodeImageProvider.cs | 2 - .../TV/TheTVDB/TvdbEpisodeProvider.cs | 8 +- .../TV/TheTVDB/TvdbPrescanTask.cs | 1 - .../TV/TheTVDB/TvdbSeasonImageProvider.cs | 2 - .../TV/TheTVDB/TvdbSeriesImageProvider.cs | 2 +- .../Users/UserMetadataService.cs | 2 +- .../Videos/VideoMetadataService.cs | 2 - .../Years/YearMetadataService.cs | 2 +- .../Devices/CameraUploadsFolder.cs | 3 - .../Playlists/ManualPlaylistsFolder.cs | 2 +- .../Providers/AlbumNfoProvider.cs | 2 +- .../Providers/ArtistNfoProvider.cs | 2 - .../Providers/BaseNfoProvider.cs | 2 - .../Providers/BaseVideoNfoProvider.cs | 2 +- .../Providers/EpisodeNfoProvider.cs | 2 - .../Providers/MovieNfoProvider.cs | 2 +- .../Providers/SeasonNfoProvider.cs | 2 - .../Providers/SeriesNfoProvider.cs | 2 - MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 2 +- .../Savers/EpisodeNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs | 2 +- MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs | 2 +- .../Net/HttpResponseStream.Managed.cs | 77 +++---- 238 files changed, 669 insertions(+), 740 deletions(-) create mode 100644 Emby.Common.Implementations/IO/ProgressStream.cs delete mode 100644 MediaBrowser.Common/IO/ProgressStream.cs (limited to 'SocketHttpListener/Net') diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs index 835088fea..8d0ee993f 100644 --- a/Emby.Common.Implementations/BaseApplicationHost.cs +++ b/Emby.Common.Implementations/BaseApplicationHost.cs @@ -31,7 +31,6 @@ using Emby.Common.Implementations.Net; using Emby.Common.Implementations.EnvironmentInfo; using Emby.Common.Implementations.Threading; using MediaBrowser.Common; -using MediaBrowser.Common.IO; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Net; diff --git a/Emby.Common.Implementations/Diagnostics/CommonProcess.cs b/Emby.Common.Implementations/Diagnostics/CommonProcess.cs index f6ca6cf9c..afd30bc47 100644 --- a/Emby.Common.Implementations/Diagnostics/CommonProcess.cs +++ b/Emby.Common.Implementations/Diagnostics/CommonProcess.cs @@ -98,6 +98,11 @@ namespace Emby.Common.Implementations.Diagnostics return _process.WaitForExit(timeMs); } + public Task WaitForExitAsync(int timeMs) + { + return Task.FromResult(_process.WaitForExit(timeMs)); + } + public void Dispose() { _process.Dispose(); diff --git a/Emby.Common.Implementations/Emby.Common.Implementations.csproj b/Emby.Common.Implementations/Emby.Common.Implementations.csproj index 7ee6a264b..de2a872cd 100644 --- a/Emby.Common.Implementations/Emby.Common.Implementations.csproj +++ b/Emby.Common.Implementations/Emby.Common.Implementations.csproj @@ -72,6 +72,7 @@ + diff --git a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs index c2a310c0e..5bd18cb80 100644 --- a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -1,7 +1,6 @@ using System.Net.Sockets; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Net; @@ -17,6 +16,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Emby.Common.Implementations.HttpClientManager; +using Emby.Common.Implementations.IO; using MediaBrowser.Model.IO; using MediaBrowser.Common; diff --git a/Emby.Common.Implementations/IO/ProgressStream.cs b/Emby.Common.Implementations/IO/ProgressStream.cs new file mode 100644 index 000000000..fb8cf86df --- /dev/null +++ b/Emby.Common.Implementations/IO/ProgressStream.cs @@ -0,0 +1,240 @@ +using System; +using System.IO; + +namespace Emby.Common.Implementations.IO +{ + /// + /// Measures progress when reading from a stream or writing to one + /// + public class ProgressStream : Stream + { + /// + /// Gets the base stream. + /// + /// The base stream. + public Stream BaseStream { get; private set; } + + /// + /// Gets or sets the bytes processed. + /// + /// The bytes processed. + private long BytesProcessed { get; set; } + /// + /// Gets or sets the length of the write. + /// + /// The length of the write. + private long WriteLength { get; set; } + + /// + /// Gets or sets the length of the read. + /// + /// The length of the read. + private long? ReadLength { get; set; } + + /// + /// Gets or sets the progress action. + /// + /// The progress action. + private Action ProgressAction { get; set; } + + /// + /// Creates the read progress stream. + /// + /// The base stream. + /// The progress action. + /// Length of the read. + /// ProgressStream. + public static ProgressStream CreateReadProgressStream(Stream baseStream, Action progressAction, long? readLength = null) + { + return new ProgressStream + { + BaseStream = baseStream, + ProgressAction = progressAction, + ReadLength = readLength + }; + } + + /// + /// Creates the write progress stream. + /// + /// The base stream. + /// The progress action. + /// Length of the write. + /// ProgressStream. + public static ProgressStream CreateWriteProgressStream(Stream baseStream, Action progressAction, long writeLength) + { + return new ProgressStream + { + BaseStream = baseStream, + ProgressAction = progressAction, + WriteLength = writeLength + }; + } + + /// + /// When overridden in a derived class, gets a value indicating whether the current stream supports reading. + /// + /// true if this instance can read; otherwise, false. + /// true if the stream supports reading; otherwise, false. + public override bool CanRead + { + get { return BaseStream.CanRead; } + } + + /// + /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking. + /// + /// true if this instance can seek; otherwise, false. + /// true if the stream supports seeking; otherwise, false. + public override bool CanSeek + { + get { return BaseStream.CanSeek; } + } + + /// + /// When overridden in a derived class, gets a value indicating whether the current stream supports writing. + /// + /// true if this instance can write; otherwise, false. + /// true if the stream supports writing; otherwise, false. + public override bool CanWrite + { + get { return BaseStream.CanWrite; } + } + + /// + /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. + /// + public override void Flush() + { + BaseStream.Flush(); + } + + /// + /// When overridden in a derived class, gets the length in bytes of the stream. + /// + /// The length. + /// A long value representing the length of the stream in bytes. + public override long Length + { + get { return BaseStream.Length; } + } + + /// + /// When overridden in a derived class, gets or sets the position within the current stream. + /// + /// The position. + /// The current position within the stream. + public override long Position + { + get { return BaseStream.Position; } + set + { + BaseStream.Position = value; + } + } + + /// + /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + public override int Read(byte[] buffer, int offset, int count) + { + var read = BaseStream.Read(buffer, offset, count); + + BytesProcessed += read; + + double percent = BytesProcessed; + percent /= ReadLength ?? BaseStream.Length; + percent *= 100; + + ProgressAction(percent); + + return read; + } + + public override int EndRead(IAsyncResult asyncResult) + { + var read = base.EndRead(asyncResult); + + BytesProcessed += read; + + double percent = BytesProcessed; + percent /= ReadLength ?? BaseStream.Length; + percent *= 100; + + ProgressAction(percent); + + return read; + } + + /// + /// When overridden in a derived class, sets the position within the current stream. + /// + /// A byte offset relative to the parameter. + /// A value of type indicating the reference point used to obtain the new position. + /// The new position within the current stream. + public override long Seek(long offset, SeekOrigin origin) + { + return BaseStream.Seek(offset, origin); + } + + /// + /// When overridden in a derived class, sets the length of the current stream. + /// + /// The desired length of the current stream in bytes. + public override void SetLength(long value) + { + BaseStream.SetLength(value); + } + + /// + /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies bytes from to the current stream. + /// The zero-based byte offset in at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + public override void Write(byte[] buffer, int offset, int count) + { + BaseStream.Write(buffer, offset, count); + + BytesProcessed += count; + + double percent = BytesProcessed; + percent /= WriteLength; + percent *= 100; + + ProgressAction(percent); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + var result = base.BeginWrite(buffer, offset, count, callback, state); + + BytesProcessed += count; + + double percent = BytesProcessed; + percent /= WriteLength; + percent *= 100; + + ProgressAction(percent); + + return result; + } + + /// + /// Releases the unmanaged resources used by the and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + if (disposing) + { + BaseStream.Dispose(); + } + base.Dispose(disposing); + } + } +} diff --git a/Emby.Common.Implementations/Net/NetAcceptSocket.cs b/Emby.Common.Implementations/Net/NetAcceptSocket.cs index 5f97fd854..5e831ac7a 100644 --- a/Emby.Common.Implementations/Net/NetAcceptSocket.cs +++ b/Emby.Common.Implementations/Net/NetAcceptSocket.cs @@ -108,6 +108,18 @@ namespace Emby.Common.Implementations.Net return completionSource.Task; } + public IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state) + { + var options = TransmitFileOptions.UseDefaultWorkerThread; + + return Socket.BeginSendFile(path, preBuffer, postBuffer, options, new AsyncCallback(FileSendCallback), state); + } + + public void EndSendFile(IAsyncResult result) + { + Socket.EndSendFile(result); + } + private void FileSendCallback(IAsyncResult ar) { // Retrieve the socket from the state object. diff --git a/Emby.Common.Implementations/Serialization/XmlSerializer.cs b/Emby.Common.Implementations/Serialization/XmlSerializer.cs index ad2708387..b5896e6b0 100644 --- a/Emby.Common.Implementations/Serialization/XmlSerializer.cs +++ b/Emby.Common.Implementations/Serialization/XmlSerializer.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Xml; using System.Xml.Serialization; -using MediaBrowser.Common.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index a5229c4fa..e93ee5990 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -86,7 +86,7 @@ namespace Emby.Dlna.ContentDirectory return HandleGetSystemUpdateID(); if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase)) - return HandleBrowse(methodParams, user, deviceId).Result; + return HandleBrowse(methodParams, user, deviceId); if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase)) return HandleXGetFeatureList(); @@ -98,10 +98,10 @@ namespace Emby.Dlna.ContentDirectory return HandleXSetBookmark(methodParams, user); if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase)) - return HandleSearch(methodParams, user, deviceId).Result; + return HandleSearch(methodParams, user, deviceId); if (string.Equals(methodName, "X_BrowseByLetter", StringComparison.OrdinalIgnoreCase)) - return HandleX_BrowseByLetter(methodParams, user, deviceId).Result; + return HandleX_BrowseByLetter(methodParams, user, deviceId); throw new ResourceNotFoundException("Unexpected control request name: " + methodName); } @@ -203,7 +203,7 @@ namespace Emby.Dlna.ContentDirectory return defaultValue; } - private async Task>> HandleBrowse(IDictionary sparams, User user, string deviceId) + private IEnumerable> HandleBrowse(IDictionary sparams, User user, string deviceId) { var id = sparams["ObjectID"]; var flag = sparams["BrowseFlag"]; @@ -263,7 +263,7 @@ namespace Emby.Dlna.ContentDirectory if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue) { - var childrenResult = (await GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount).ConfigureAwait(false)); + var childrenResult = (GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount)); _didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id); } @@ -276,7 +276,7 @@ namespace Emby.Dlna.ContentDirectory } else { - var childrenResult = (await GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount).ConfigureAwait(false)); + var childrenResult = (GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount)); totalCount = childrenResult.TotalRecordCount; provided = childrenResult.Items.Length; @@ -288,7 +288,7 @@ namespace Emby.Dlna.ContentDirectory if (childItem.IsDisplayedAsFolder || displayStubType.HasValue) { - var childCount = (await GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0).ConfigureAwait(false)) + var childCount = (GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0)) .TotalRecordCount; _didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter); @@ -314,13 +314,13 @@ namespace Emby.Dlna.ContentDirectory }; } - private Task>> HandleX_BrowseByLetter(IDictionary sparams, User user, string deviceId) + private IEnumerable> HandleX_BrowseByLetter(IDictionary sparams, User user, string deviceId) { // TODO: Implement this method return HandleSearch(sparams, user, deviceId); } - private async Task>> HandleSearch(IDictionary sparams, User user, string deviceId) + private IEnumerable> HandleSearch(IDictionary sparams, User user, string deviceId) { var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", "")); var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", "")); @@ -374,7 +374,7 @@ namespace Emby.Dlna.ContentDirectory var item = serverItem.Item; - var childrenResult = (await GetChildrenSorted(item, user, searchCriteria, sortCriteria, start, requestedCount).ConfigureAwait(false)); + var childrenResult = (GetChildrenSorted(item, user, searchCriteria, sortCriteria, start, requestedCount)); totalCount = childrenResult.TotalRecordCount; @@ -384,7 +384,7 @@ namespace Emby.Dlna.ContentDirectory { if (i.IsDisplayedAsFolder) { - var childCount = (await GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0).ConfigureAwait(false)) + var childCount = (GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0)) .TotalRecordCount; _didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter); @@ -410,7 +410,7 @@ namespace Emby.Dlna.ContentDirectory }; } - private Task> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit) { var folder = (Folder)item; @@ -470,7 +470,7 @@ namespace Emby.Dlna.ContentDirectory return new DtoOptions(true); } - private async Task> GetUserItems(BaseItem item, StubType? stubType, User user, SortCriteria sort, int? startIndex, int? limit) + private QueryResult GetUserItems(BaseItem item, StubType? stubType, User user, SortCriteria sort, int? startIndex, int? limit) { if (item is MusicGenre) { @@ -518,15 +518,15 @@ namespace Emby.Dlna.ContentDirectory StartIndex = startIndex, User = user, IsMissing = false, - PresetViews = new[] {CollectionType.Movies, CollectionType.TvShows, CollectionType.Music}, - ExcludeItemTypes = new[] {typeof (Game).Name, typeof (Book).Name}, + PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music }, + ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name }, IsPlaceHolder = false, DtoOptions = GetDtoOptions() }; SetSorting(query, sort, folder.IsPreSorted); - var queryResult = await folder.GetItems(query).ConfigureAwait(false); + var queryResult = folder.GetItems(query); return ToResult(queryResult); } @@ -557,8 +557,8 @@ namespace Emby.Dlna.ContentDirectory { Recursive = true, ParentId = parentId, - GenreIds = new[] {item.Id.ToString("N")}, - IncludeItemTypes = new[] {typeof (MusicAlbum).Name}, + GenreIds = new[] { item.Id.ToString("N") }, + IncludeItemTypes = new[] { typeof(MusicAlbum).Name }, Limit = limit, StartIndex = startIndex, DtoOptions = GetDtoOptions() diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index c308d9c63..e22bf45c8 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -18,6 +18,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Text; +using System.Threading.Tasks; using System.Xml; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Configuration; @@ -111,14 +112,14 @@ namespace Emby.Dlna.Didl } } - public void WriteItemElement(DlnaOptions options, - XmlWriter writer, - BaseItem item, + public void WriteItemElement(DlnaOptions options, + XmlWriter writer, + BaseItem item, User user, - BaseItem context, - StubType? contextStubType, - string deviceId, - Filter filter, + BaseItem context, + StubType? contextStubType, + string deviceId, + Filter filter, StreamInfo streamInfo = null) { var clientId = GetClientId(item, null); @@ -920,7 +921,7 @@ namespace Emby.Dlna.Didl if (item is Video) { - var userData = _userDataManager.GetUserDataDto(item, _user).Result; + var userData = _userDataManager.GetUserDataDto(item, _user); playbackPercentage = Convert.ToInt32(userData.PlayedPercentage ?? 0); if (playbackPercentage >= 100 || userData.Played) @@ -930,7 +931,7 @@ namespace Emby.Dlna.Didl } else if (item is Series || item is Season || item is BoxSet) { - var userData = _userDataManager.GetUserDataDto(item, _user).Result; + var userData = _userDataManager.GetUserDataDto(item, _user); if (userData.Played) { diff --git a/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs b/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs index 58c6cfe82..2ec58ff28 100644 --- a/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs +++ b/Emby.Drawing.ImageMagick/PlayedIndicatorDrawer.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Drawing; using System; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Drawing.ImageMagick/StripCollageBuilder.cs b/Emby.Drawing.ImageMagick/StripCollageBuilder.cs index 715ab4680..63cf8fe5f 100644 --- a/Emby.Drawing.ImageMagick/StripCollageBuilder.cs +++ b/Emby.Drawing.ImageMagick/StripCollageBuilder.cs @@ -2,7 +2,7 @@ using MediaBrowser.Common.Configuration; using System; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Drawing.ImageMagick/UnplayedCountIndicator.cs b/Emby.Drawing.ImageMagick/UnplayedCountIndicator.cs index c53140099..ee685c3c5 100644 --- a/Emby.Drawing.ImageMagick/UnplayedCountIndicator.cs +++ b/Emby.Drawing.ImageMagick/UnplayedCountIndicator.cs @@ -2,8 +2,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Drawing; using System.Globalization; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace Emby.Drawing.ImageMagick diff --git a/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs b/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs index 9f3a74eb7..ad3b5226c 100644 --- a/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs +++ b/Emby.Drawing.Skia/PlayedIndicatorDrawer.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Drawing; using System; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using System.Reflection; diff --git a/Emby.Drawing.Skia/UnplayedCountIndicator.cs b/Emby.Drawing.Skia/UnplayedCountIndicator.cs index f0283ad23..56a2519a3 100644 --- a/Emby.Drawing.Skia/UnplayedCountIndicator.cs +++ b/Emby.Drawing.Skia/UnplayedCountIndicator.cs @@ -4,7 +4,7 @@ using MediaBrowser.Common.Net; using MediaBrowser.Model.Drawing; using System.Globalization; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Drawing/Common/ImageHeader.cs b/Emby.Drawing/Common/ImageHeader.cs index c385779a1..4f56498a5 100644 --- a/Emby.Drawing/Common/ImageHeader.cs +++ b/Emby.Drawing/Common/ImageHeader.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index d5a3b73c2..a1543382f 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -17,7 +17,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using Emby.Drawing.Common; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Net; diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 7a13334e4..690e4c488 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -589,7 +589,7 @@ namespace Emby.Server.Core FileOrganizationRepository = GetFileOrganizationRepository(); RegisterSingleInstance(FileOrganizationRepository); - AuthenticationRepository = await GetAuthenticationRepository().ConfigureAwait(false); + AuthenticationRepository = GetAuthenticationRepository(); RegisterSingleInstance(AuthenticationRepository); UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider, _defaultUserNameFactory()); @@ -948,7 +948,7 @@ namespace Emby.Server.Core return repo; } - private async Task GetAuthenticationRepository() + private IAuthenticationRepository GetAuthenticationRepository() { var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths); diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index 067260dfd..809771b04 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -23,7 +23,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; @@ -120,7 +120,7 @@ namespace Emby.Server.Implementations.Channels if (query.IsFavorite.HasValue) { var val = query.IsFavorite.Value; - channels = channels.Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val) + channels = channels.Where(i => _userDataManager.GetUserData(user, i).IsFavorite == val) .ToList(); } @@ -263,7 +263,7 @@ namespace Emby.Server.Implementations.Channels } catch { - + } return; } @@ -273,7 +273,7 @@ namespace Emby.Server.Implementations.Channels _jsonSerializer.SerializeToFile(mediaSources, path); } - public async Task> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken) + public IEnumerable GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken) { IEnumerable results = GetSavedMediaSources(item); @@ -963,7 +963,7 @@ namespace Emby.Server.Implementations.Channels } } - return await GetReturnItems(internalItems, providerTotalRecordCount, user, query).ConfigureAwait(false); + return GetReturnItems(internalItems, providerTotalRecordCount, user, query); } public async Task> GetChannelItems(ChannelItemQuery query, CancellationToken cancellationToken) @@ -1154,7 +1154,7 @@ namespace Emby.Server.Implementations.Channels filename + ".json"); } - private async Task> GetReturnItems(IEnumerable items, + private QueryResult GetReturnItems(IEnumerable items, int? totalCountFromProvider, User user, ChannelItemQuery query) diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs index aafb13329..463d276e5 100644 --- a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs +++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs @@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Collections return base.Supports(item); } - protected override Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var playlist = (BoxSet)item; @@ -73,10 +73,10 @@ namespace Emby.Server.Implementations.Collections .DistinctBy(i => i.Id) .ToList(); - return Task.FromResult(GetFinalItems(items, 2)); + return GetFinalItems(items, 2); } - protected string CreateImage(IHasImages item, List itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) + protected override string CreateImage(IHasImages item, List itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) { return CreateSingleImage(itemsWithImages, outputPathWithoutExtension, ImageType.Primary); } diff --git a/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs index 4ff33e645..c7bcdfe25 100644 --- a/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs +++ b/Emby.Server.Implementations/Collections/CollectionsDynamicFolder.cs @@ -1,7 +1,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using System.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs b/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs index e2d5d0272..52979f085 100644 --- a/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs +++ b/Emby.Server.Implementations/Devices/CameraUploadsDynamicFolder.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Providers; diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index b246ef196..027a55516 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -16,7 +16,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 6f2e437cf..45fbd69dc 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Extensions; @@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Dto foreach (var item in items) { - var dto = await GetBaseItemDtoInternal(item, options, user, owner).ConfigureAwait(false); + var dto = GetBaseItemDtoInternal(item, options, user, owner); var tvChannel = item as LiveTvChannel; if (tvChannel != null) @@ -160,7 +160,7 @@ namespace Emby.Server.Implementations.Dto { var syncDictionary = GetSyncedItemProgress(options); - var dto = GetBaseItemDtoInternal(item, options, user, owner).Result; + var dto = GetBaseItemDtoInternal(item, options, user, owner); var tvChannel = item as LiveTvChannel; if (tvChannel != null) { @@ -292,7 +292,7 @@ namespace Emby.Server.Implementations.Dto } } - private async Task GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) + private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) { var fields = options.Fields; @@ -341,7 +341,7 @@ namespace Emby.Server.Implementations.Dto if (user != null) { - await AttachUserSpecificInfo(dto, item, user, options).ConfigureAwait(false); + AttachUserSpecificInfo(dto, item, user, options); } var hasMediaSources = item as IHasMediaSources; @@ -402,7 +402,7 @@ namespace Emby.Server.Implementations.Dto public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List taggedItems, Dictionary syncProgress, User user = null) { - var dto = GetBaseItemDtoInternal(item, options, user).Result; + var dto = GetBaseItemDtoInternal(item, options, user); if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts)) { @@ -455,7 +455,7 @@ namespace Emby.Server.Implementations.Dto /// /// Attaches the user specific info. /// - private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions) + private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions) { var fields = dtoOptions.Fields; @@ -465,7 +465,7 @@ namespace Emby.Server.Implementations.Dto if (dtoOptions.EnableUserData) { - dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user, dtoOptions.Fields).ConfigureAwait(false); + dto.UserData = _userDataRepository.GetUserDataDto(item, dto, user, dtoOptions.Fields); } if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library) @@ -497,7 +497,7 @@ namespace Emby.Server.Implementations.Dto { if (dtoOptions.EnableUserData) { - dto.UserData = await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false); + dto.UserData = _userDataRepository.GetUserDataDto(item, user); } } diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs index b93410180..71e31d4d4 100644 --- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs @@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.EntryPoints .DistinctBy(i => i.Id) .Select(i => { - var dto = _userDataManager.GetUserDataDto(i, user).Result; + var dto = _userDataManager.GetUserDataDto(i, user); dto.ItemId = i.Id.ToString("N"); return dto; }) diff --git a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 7371b4fdb..cf9fdbb16 100644 --- a/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/Emby.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -15,7 +15,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Library; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs b/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs index 4094e6b9b..d95bd8734 100644 --- a/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs +++ b/Emby.Server.Implementations/FileOrganization/FileOrganizationService.cs @@ -17,7 +17,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Events; using MediaBrowser.Common.Events; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.Tasks; diff --git a/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs index 5be7ba7ad..b71a3975f 100644 --- a/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs +++ b/Emby.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs @@ -8,7 +8,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Tasks; diff --git a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs index 2cbf2613e..0dbd6f837 100644 --- a/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs +++ b/Emby.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -10,7 +10,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index f085ff71e..a51ea5726 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -34,6 +34,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp private readonly bool _enableDualMode; private readonly IEnvironmentInfo _environment; + private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); + private CancellationToken _disposeCancellationToken; + public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, bool enableDualMode, Func httpRequestFactory, IFileSystem fileSystem, IEnvironmentInfo environment) { _logger = logger; @@ -48,6 +51,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp _httpRequestFactory = httpRequestFactory; _fileSystem = fileSystem; _environment = environment; + + _disposeCancellationToken = _disposeCancellationTokenSource.Token; } public Action ErrorHandler { get; set; } @@ -83,7 +88,7 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp private void ProcessContext(HttpListenerContext context) { //Task.Factory.StartNew(() => InitTask(context), TaskCreationOptions.DenyChildAttach | TaskCreationOptions.PreferFairness); - Task.Run(() => InitTask(context, CancellationToken.None)); + Task.Run(() => InitTask(context, _disposeCancellationToken)); } private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken) @@ -173,6 +178,8 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp public void Stop() { + _disposeCancellationTokenSource.Cancel(); + if (_listener != null) { foreach (var prefix in _listener.Prefixes.ToList()) diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs index 33378949c..5d42f42fa 100644 --- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs +++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.Services; namespace Emby.Server.Implementations.HttpServer diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 885cfa3c8..7b9083f00 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs index 0b1391ae0..aef53751e 100644 --- a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs +++ b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 19681a832..b8ce23a42 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -12,7 +12,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.IO; @@ -59,33 +59,6 @@ namespace Emby.Server.Implementations.Images //return GetSupportedImages(item).Where(i => IsEnabled(options, i, item)).ToList(); } - private bool IsEnabled(MetadataOptions options, ImageType type, IHasImages item) - { - if (type == ImageType.Backdrop) - { - if (item.LockedFields.Contains(MetadataFields.Backdrops)) - { - return false; - } - } - else if (type == ImageType.Screenshot) - { - if (item.LockedFields.Contains(MetadataFields.Screenshots)) - { - return false; - } - } - else - { - if (item.LockedFields.Contains(MetadataFields.Images)) - { - return false; - } - } - - return options.IsEnabled(type); - } - public async Task FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellationToken) { if (!Supports(item)) @@ -128,7 +101,7 @@ namespace Emby.Server.Implementations.Images } } - var items = await GetItemsWithImages(item).ConfigureAwait(false); + var items = GetItemsWithImages(item); return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false); } @@ -159,7 +132,7 @@ namespace Emby.Server.Implementations.Images return ItemUpdateType.ImageUpdate; } - protected abstract Task> GetItemsWithImages(IHasImages item); + protected abstract List GetItemsWithImages(IHasImages item); protected string CreateThumbCollage(IHasImages primaryItem, List items, string outputPath) { diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index 64f025d93..54f9ca392 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -6,7 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 394e357c7..94bd4e0d4 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -40,7 +40,7 @@ using MediaBrowser.Model.Net; using SortOrder = MediaBrowser.Model.Entities.SortOrder; using VideoResolver = MediaBrowser.Naming.Video.VideoResolver; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Tasks; diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs index 1d3cacc1d..24dc1104a 100644 --- a/Emby.Server.Implementations/Library/ResolverHelper.cs +++ b/Emby.Server.Implementations/Library/ResolverHelper.cs @@ -5,8 +5,6 @@ using System; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Library diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index b3d6d4ad7..806e20f00 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -8,7 +8,7 @@ using MediaBrowser.Naming.Audio; using System; using System.Collections.Generic; using System.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 2971405b9..2ad839673 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Logging; using System; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 3550a83b9..69563e5a0 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -11,7 +11,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs index 1bec1073d..6c7c1f052 100644 --- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Resolvers; using System; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index e5cad9f91..60260e98a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -10,7 +10,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs index 5a14edf13..e066ab61b 100644 --- a/Emby.Server.Implementations/Library/UserDataManager.cs +++ b/Emby.Server.Implementations/Library/UserDataManager.cs @@ -182,21 +182,21 @@ namespace Emby.Server.Implementations.Library return GetUserData(userId, item.Id, item.GetUserDataKeys()); } - public async Task GetUserDataDto(IHasUserData item, User user) + public UserItemDataDto GetUserDataDto(IHasUserData item, User user) { var userData = GetUserData(user.Id, item); var dto = GetUserItemDataDto(userData); - await item.FillUserDataDtoValues(dto, userData, null, user, new List()).ConfigureAwait(false); + item.FillUserDataDtoValues(dto, userData, null, user, new List()); return dto; } - public async Task GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List fields) + public UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List fields) { var userData = GetUserData(user.Id, item); var dto = GetUserItemDataDto(userData); - await item.FillUserDataDtoValues(dto, userData, itemDto, user, fields).ConfigureAwait(false); + item.FillUserDataDtoValues(dto, userData, itemDto, user, fields); return dto; } diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index 7ebfd71c0..ef3b86abf 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index e43e05839..dcfaaa9d7 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -3,7 +3,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Common.Net; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 83db58668..6ce2b88f1 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -28,7 +28,7 @@ using System.Xml; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -1636,7 +1636,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - var episodesToDelete = (await librarySeries.GetItems(new InternalItemsQuery + var episodesToDelete = (librarySeries.GetItems(new InternalItemsQuery { SortBy = new[] { ItemSortBy.DateCreated }, SortOrder = SortOrder.Descending, @@ -1645,7 +1645,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV Recursive = true, DtoOptions = new DtoOptions(true) - }).ConfigureAwait(false)) + })) .Items .Where(i => i.LocationType == LocationType.FileSystem && _fileSystem.FileExists(i.Path)) .Skip(seriesTimer.KeepUpTo - 1) @@ -1785,7 +1785,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV throw new InvalidOperationException("Emby DVR Requires an active Emby Premiere subscription."); } - private async void OnSuccessfulRecording(TimerInfo timer, string path) + private void OnSuccessfulRecording(TimerInfo timer, string path) { //if (timer.IsProgramSeries && GetConfiguration().EnableAutoOrganize) //{ diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index cec158633..6173068cc 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 953cb8e41..4ba2269a6 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs index 7bf6bf1ca..843ba7e42 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/SeriesTimerManager.cs @@ -2,8 +2,6 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.LiveTv.EmbyTV diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs index 2eec3df8a..380b24800 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs @@ -8,7 +8,7 @@ using System.Collections.Concurrent; using System.Globalization; using System.Linq; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 48ad7cf12..c2f057560 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -26,7 +26,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common.Events; -using MediaBrowser.Common.IO; + using MediaBrowser.Common.Security; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index 4dd6e3c71..41b058baf 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -115,7 +115,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var lockkeyMsg = CreateGetMessage(tuner, "lockkey"); await socket.SendToAsync(lockkeyMsg, 0, lockkeyMsg.Length, ipEndPoint, cancellationToken); - var response = await socket.ReceiveAsync(cancellationToken).ConfigureAwait(false); + + var receiveBuffer = new byte[8192]; + var response = await socket.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false); + string returnVal; ParseReturnMessage(response.Buffer, response.ReceivedBytes, out returnVal); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index 2c6641ee1..12b7901f9 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 8c4b9bf60..4c1190e0e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.IO; diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 884a001f0..1d74e8788 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -13,7 +13,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Library; diff --git a/Emby.Server.Implementations/Migrations/GuideMigration.cs b/Emby.Server.Implementations/Migrations/GuideMigration.cs index 99b2942dc..78fb6c222 100644 --- a/Emby.Server.Implementations/Migrations/GuideMigration.cs +++ b/Emby.Server.Implementations/Migrations/GuideMigration.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Migrations _taskManager = taskManager; } - public async Task Run() + public Task Run() { var name = "GuideRefresh3"; @@ -42,6 +42,8 @@ namespace Emby.Server.Implementations.Migrations _config.Configuration.Migrations = list.ToArray(); _config.SaveConfiguration(); } + + return Task.FromResult(true); } } } diff --git a/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs b/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs index bd185bc9c..9d7f67a4f 100644 --- a/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs +++ b/Emby.Server.Implementations/Migrations/LibraryScanMigration.cs @@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Migrations _taskManager = taskManager; } - public async Task Run() + public Task Run() { var name = "LibraryScan6"; @@ -42,6 +42,8 @@ namespace Emby.Server.Implementations.Migrations _config.Configuration.Migrations = list.ToArray(); _config.SaveConfiguration(); } + + return Task.FromResult(true); } } } diff --git a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs index c425a761a..0744fc0d9 100644 --- a/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs +++ b/Emby.Server.Implementations/Photos/PhotoAlbumImageProvider.cs @@ -18,12 +18,12 @@ namespace Emby.Server.Implementations.Photos { } - protected override Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var photoAlbum = (PhotoAlbum)item; var items = GetFinalItems(photoAlbum.Children.ToList()); - return Task.FromResult(items); + return items; } protected string CreateImage(IHasImages item, List itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) diff --git a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs index 75124cab8..127ce24ae 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Emby.Server.Implementations.Images; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.IO; @@ -27,7 +27,7 @@ namespace Emby.Server.Implementations.Playlists { } - protected override Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var playlist = (Playlist)item; @@ -68,7 +68,7 @@ namespace Emby.Server.Implementations.Playlists .DistinctBy(i => i.Id) .ToList(); - return Task.FromResult(GetFinalItems(items)); + return GetFinalItems(items); } } @@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.Playlists _libraryManager = libraryManager; } - protected override Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var items = _libraryManager.GetItemList(new InternalItemsQuery { @@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.Playlists }).ToList(); - return Task.FromResult(GetFinalItems(items)); + return GetFinalItems(items); } //protected override Task CreateImage(IHasImages item, List itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) @@ -113,7 +113,7 @@ namespace Emby.Server.Implementations.Playlists _libraryManager = libraryManager; } - protected override Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var items = _libraryManager.GetItemList(new InternalItemsQuery { @@ -127,7 +127,7 @@ namespace Emby.Server.Implementations.Playlists }).ToList(); - return Task.FromResult(GetFinalItems(items)); + return GetFinalItems(items); } //protected override Task CreateImage(IHasImages item, List itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 6a290c664..474ef0f53 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -12,7 +12,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -164,7 +164,7 @@ namespace Emby.Server.Implementations.Playlists return path; } - private Task> GetPlaylistItems(IEnumerable itemIds, string playlistMediaType, User user, DtoOptions options) + private IEnumerable GetPlaylistItems(IEnumerable itemIds, string playlistMediaType, User user, DtoOptions options) { var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null); @@ -192,7 +192,7 @@ namespace Emby.Server.Implementations.Playlists var list = new List(); - var items = (await GetPlaylistItems(itemIds, playlist.MediaType, user, options).ConfigureAwait(false)) + var items = (GetPlaylistItems(itemIds, playlist.MediaType, user, options)) .Where(i => i.SupportsAddingToPlaylist) .ToList(); @@ -278,7 +278,7 @@ namespace Emby.Server.Implementations.Playlists { var typeName = "PlaylistsFolder"; - return _libraryManager.RootFolder.Children.OfType().FirstOrDefault(i => string.Equals(i.GetType().Name, typeName, StringComparison.Ordinal)) ?? + return _libraryManager.RootFolder.Children.OfType().FirstOrDefault(i => string.Equals(i.GetType().Name, typeName, StringComparison.Ordinal)) ?? _libraryManager.GetUserRootFolder().Children.OfType().FirstOrDefault(i => string.Equals(i.GetType().Name, typeName, StringComparison.Ordinal)); } } diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs index 22d54831e..967e7ddd8 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs @@ -10,7 +10,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs b/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs index 749233fa1..9bf6f2824 100644 --- a/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/RefreshIntrosTask.cs @@ -4,7 +4,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/Emby.Server.Implementations/ServerManager/ServerManager.cs b/Emby.Server.Implementations/ServerManager/ServerManager.cs index 4c9228e54..7cd94c526 100644 --- a/Emby.Server.Implementations/ServerManager/ServerManager.cs +++ b/Emby.Server.Implementations/ServerManager/ServerManager.cs @@ -12,7 +12,7 @@ using System.Collections.Specialized; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using MediaBrowser.Model.Text; diff --git a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs index ac20fe7b3..e4392d7e6 100644 --- a/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs +++ b/Emby.Server.Implementations/ServerManager/WebSocketConnection.cs @@ -9,7 +9,6 @@ using System.Collections.Specialized; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using MediaBrowser.Model.Text; diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs index 58ee22ecb..84dc343c3 100644 --- a/Emby.Server.Implementations/Services/ResponseHelper.cs +++ b/Emby.Server.Implementations/Services/ResponseHelper.cs @@ -124,7 +124,7 @@ namespace Emby.Server.Implementations.Services response.ContentType = "application/octet-stream"; response.SetContentLength(bytes.Length); - await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false); return; } @@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Services { bytes = Encoding.UTF8.GetBytes(responseText); response.SetContentLength(bytes.Length); - await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); + await response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false); return; } diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs index d283bf81f..1c530144c 100644 --- a/Emby.Server.Implementations/Services/ServiceController.cs +++ b/Emby.Server.Implementations/Services/ServiceController.cs @@ -187,7 +187,7 @@ namespace Emby.Server.Implementations.Services return null; } - public async Task Execute(HttpListenerHost appHost, object requestDto, IRequest req) + public Task Execute(HttpListenerHost appHost, object requestDto, IRequest req) { req.Dto = requestDto; var requestType = requestDto.GetType(); @@ -209,9 +209,7 @@ namespace Emby.Server.Implementations.Services req.Dto = requestDto; //Executes the service and returns the result - var response = await ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName()).ConfigureAwait(false); - - return response; + return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName()); } } diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs index 95a9dd682..526e62d39 100644 --- a/Emby.Server.Implementations/Services/ServiceHandler.cs +++ b/Emby.Server.Implementations/Services/ServiceHandler.cs @@ -143,7 +143,8 @@ namespace Emby.Server.Implementations.Services var rawResponse = await appHost.ServiceController.Execute(appHost, request, httpReq).ConfigureAwait(false); - var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false); + //var response = await HandleResponseAsync(rawResponse).ConfigureAwait(false); + var response = rawResponse; // Apply response filters foreach (var responseFilter in appHost.ResponseFilters) diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 6b3d2dc52..42cd5d1b1 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -985,7 +985,7 @@ namespace Emby.Server.Implementations.Session var list = new List(); foreach (var itemId in command.ItemIds) { - var subItems = await TranslateItemForPlayback(itemId, user).ConfigureAwait(false); + var subItems = TranslateItemForPlayback(itemId, user); list.AddRange(subItems); } @@ -1052,7 +1052,7 @@ namespace Emby.Server.Implementations.Session await session.SessionController.SendPlayCommand(command, cancellationToken).ConfigureAwait(false); } - private async Task> TranslateItemForPlayback(string id, User user) + private List TranslateItemForPlayback(string id, User user) { var item = _libraryManager.GetItemById(id); @@ -1089,7 +1089,7 @@ namespace Emby.Server.Implementations.Session { var folder = (Folder)item; - var itemsResult = await folder.GetItems(new InternalItemsQuery(user) + var itemsResult = folder.GetItems(new InternalItemsQuery(user) { Recursive = true, IsFolder = false, @@ -1102,7 +1102,7 @@ namespace Emby.Server.Implementations.Session } } - }).ConfigureAwait(false); + }); return FilterToSingleMediaType(itemsResult.Items) .OrderBy(i => i.SortName) diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs index 478f9da71..2735bb237 100644 --- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs @@ -57,7 +57,6 @@ namespace Emby.Server.Implementations.Session _json = json; _httpServer = httpServer; _serverManager = serverManager; - httpServer.WebSocketConnecting += _httpServer_WebSocketConnecting; serverManager.WebSocketConnected += _serverManager_WebSocketConnected; } @@ -84,27 +83,6 @@ namespace Emby.Server.Implementations.Session } } - async void _httpServer_WebSocketConnecting(object sender, WebSocketConnectingEventArgs e) - { - //var token = e.QueryString["api_key"]; - //if (!string.IsNullOrWhiteSpace(token)) - //{ - // try - // { - // var session = await GetSession(e.QueryString, e.Endpoint).ConfigureAwait(false); - - // if (session == null) - // { - // e.AllowConnection = false; - // } - // } - // catch (Exception ex) - // { - // _logger.ErrorException("Error getting session info", ex); - // } - //} - } - private Task GetSession(QueryParamCollection queryString, string remoteEndpoint) { if (queryString == null) @@ -123,7 +101,6 @@ namespace Emby.Server.Implementations.Session public void Dispose() { - _httpServer.WebSocketConnecting -= _httpServer_WebSocketConnecting; _serverManager.WebSocketConnected -= _serverManager_WebSocketConnected; } diff --git a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs index 376696536..f54613384 100644 --- a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs @@ -11,7 +11,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using Emby.Server.Implementations.Images; -using MediaBrowser.Common.IO; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Dto; @@ -37,20 +36,20 @@ namespace Emby.Server.Implementations.UserViews }; } - protected override async Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var view = (CollectionFolder)item; var recursive = !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); - var result = await view.GetItems(new InternalItemsQuery + var result = view.GetItems(new InternalItemsQuery { CollapseBoxSetItems = false, Recursive = recursive, ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" }, DtoOptions = new DtoOptions(false) - }).ConfigureAwait(false); + }); var items = result.Items.Select(i => { @@ -135,7 +134,7 @@ namespace Emby.Server.Implementations.UserViews }; } - protected override async Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var view = (ManualCollectionsFolder)item; diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs index 06f7d73e5..cd2c4728f 100644 --- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.UserViews }; } - protected override async Task> GetItemsWithImages(IHasImages item) + protected override List GetItemsWithImages(IHasImages item) { var view = (UserView)item; @@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.UserViews if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) || string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase)) { - var userItemsResult = await view.GetItems(new InternalItemsQuery + var userItemsResult = view.GetItems(new InternalItemsQuery { CollapseBoxSetItems = false, DtoOptions = new DtoOptions(false) @@ -82,15 +82,14 @@ namespace Emby.Server.Implementations.UserViews var isUsingCollectionStrip = IsUsingCollectionStrip(view); var recursive = isUsingCollectionStrip && !new[] { CollectionType.Channels, CollectionType.BoxSets, CollectionType.Playlists }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase); - var result = await view.GetItems(new InternalItemsQuery + var result = view.GetItems(new InternalItemsQuery { User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null, CollapseBoxSetItems = false, Recursive = recursive, ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Person" }, DtoOptions = new DtoOptions(false) - - }).ConfigureAwait(false); + }); var items = result.Items.Select(i => { diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 53e474982..e4abe96f3 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -15,7 +15,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Diagnostics; @@ -399,7 +399,7 @@ namespace MediaBrowser.Api } } - private async void PingTimer(TranscodingJob job, bool isProgressCheckIn) + private void PingTimer(TranscodingJob job, bool isProgressCheckIn) { if (job.HasExited) { diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 5dbb4b42a..8d5f46962 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Controller.MediaEncoding; @@ -113,8 +113,7 @@ namespace MediaBrowser.Api public void Post(UpdateMediaEncoderPath request) { - var task = _mediaEncoder.UpdateEncoderPath(request.Path, request.PathType); - Task.WaitAll(task); + _mediaEncoder.UpdateEncoderPath(request.Path, request.PathType); } /// diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs index 8125951b5..6e59cceec 100644 --- a/MediaBrowser.Api/Dlna/DlnaServerService.cs +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index dc2f8e136..a1f891506 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Api _userManager = userManager; } - public async Task Get(GetQueryFilters request) + public object Get(GetQueryFilters request) { var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId); var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; @@ -61,7 +61,7 @@ namespace MediaBrowser.Api user == null ? _libraryManager.RootFolder : user.RootFolder : parentItem; - var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)); + var result = ((Folder)item).GetItems(GetItemsQuery(request, user)); return ToOptimizedResult(GetFilters(result.Items)); } diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs index 2c8fc2d61..2100e9e91 100644 --- a/MediaBrowser.Api/Images/ImageByNameService.cs +++ b/MediaBrowser.Api/Images/ImageByNameService.cs @@ -8,8 +8,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 6c4cc2217..882967a53 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -14,7 +14,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Api/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index ebd8b8951..e4f3fd3d7 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -14,7 +14,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; @@ -141,11 +141,6 @@ namespace MediaBrowser.Api.Images { var item = _libraryManager.GetItemById(request.Id); - return await GetRemoteImageResult(item, request).ConfigureAwait(false); - } - - private async Task GetRemoteImageResult(BaseItem item, BaseRemoteImageRequest request) - { var images = await _providerManager.GetAvailableRemoteImages(item, new RemoteImageQuery { ProviderName = request.ProviderName, diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs index bca292241..534089848 100644 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ b/MediaBrowser.Api/ItemRefreshService.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Providers; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 31292618d..4e0bdc8a9 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -21,7 +21,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index c3bb80dcb..8e396ff57 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index a90c8d9e7..837a0f6a6 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -17,7 +17,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Api.Playback.Progressive; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index 0ff52e63f..52cc02528 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -5,7 +5,7 @@ using System; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index c0257b007..af8670eb1 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -9,8 +9,6 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Net; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index d4d468913..9061261f5 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Net; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/Reports/ReportsService.cs b/MediaBrowser.Api/Reports/ReportsService.cs index 6e89b0d39..d4201e73c 100644 --- a/MediaBrowser.Api/Reports/ReportsService.cs +++ b/MediaBrowser.Api/Reports/ReportsService.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Api.Reports /// Gets the given request. /// The request. /// A Task<object> - public async Task Get(GetReportHeaders request) + public object Get(GetReportHeaders request) { if (string.IsNullOrEmpty(request.IncludeItemTypes)) return null; @@ -95,14 +95,14 @@ namespace MediaBrowser.Api.Reports /// Gets the given request. /// The request. /// A Task<object> - public async Task Get(GetItemReport request) + public object Get(GetItemReport request) { if (string.IsNullOrEmpty(request.IncludeItemTypes)) return null; request.DisplayType = "Screen"; var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; - var reportResult = await GetReportResult(request, user); + var reportResult = GetReportResult(request, user); return ToOptimizedResult(reportResult); } @@ -110,7 +110,7 @@ namespace MediaBrowser.Api.Reports /// Gets the given request. /// The request. /// A Task<object> - public async Task Get(GetReportDownload request) + public object Get(GetReportDownload request) { if (string.IsNullOrEmpty(request.IncludeItemTypes)) return null; @@ -142,7 +142,7 @@ namespace MediaBrowser.Api.Reports case ReportViewType.ReportData: ReportIncludeItemTypes reportRowType = ReportHelper.GetRowType(request.IncludeItemTypes); ReportBuilder dataBuilder = new ReportBuilder(_libraryManager); - QueryResult queryResult = await GetQueryResult(request, user).ConfigureAwait(false); + QueryResult queryResult = GetQueryResult(request, user); result = dataBuilder.GetResult(queryResult.Items, request); result.TotalRecordCount = queryResult.TotalRecordCount; break; @@ -314,7 +314,7 @@ namespace MediaBrowser.Api.Reports return query; } - private async Task> GetQueryResult(BaseReportRequest request, User user) + private QueryResult GetQueryResult(BaseReportRequest request, User user) { // all report queries currently need this because it's not being specified request.Recursive = true; @@ -344,7 +344,7 @@ namespace MediaBrowser.Api.Reports { request.Recursive = true; var query = GetItemsQuery(request, user); - var result = await folder.GetItems(query).ConfigureAwait(false); + var result = folder.GetItems(query); if (string.IsNullOrWhiteSpace(request.SortBy)) { @@ -359,19 +359,19 @@ namespace MediaBrowser.Api.Reports if (request.Recursive) { - return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); + return folder.GetItems(GetItemsQuery(request, user)); } if (user == null) { - return await folder.GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); + return folder.GetItems(GetItemsQuery(request, null)); } var userRoot = item as UserRootFolder; if (userRoot == null) { - return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); + return folder.GetItems(GetItemsQuery(request, user)); } IEnumerable items = folder.GetChildren(user, true); @@ -412,10 +412,10 @@ namespace MediaBrowser.Api.Reports /// Gets report result. /// The request. /// The report result. - private async Task GetReportResult(GetItemReport request, User user) + private ReportResult GetReportResult(GetItemReport request, User user) { ReportBuilder reportBuilder = new ReportBuilder(_libraryManager); - QueryResult queryResult = await GetQueryResult(request, user).ConfigureAwait(false); + QueryResult queryResult = GetQueryResult(request, user); ReportResult reportResult = reportBuilder.GetResult(queryResult.Items, request); reportResult.TotalRecordCount = queryResult.TotalRecordCount; diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index 798004a5e..7dde974ae 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -14,7 +14,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index 913b23062..a9cec0914 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 02114399a..5a6004760 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -432,14 +432,14 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException("Series not found"); } - var seasons = (await series.GetItems(new InternalItemsQuery(user) + var seasons = (series.GetItems(new InternalItemsQuery(user) { IsMissing = request.IsMissing, IsVirtualUnaired = request.IsVirtualUnaired, IsSpecialSeason = request.IsSpecialSeason, AdjacentTo = request.AdjacentTo - }).ConfigureAwait(false)).Items.OfType(); + })).Items.OfType(); var dtoOptions = GetDtoOptions(_authContext, request); diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index d4811e603..01e1ce769 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.Api.UserLibrary var dtoOptions = GetDtoOptions(_authContext, request); - var result = await GetQueryResult(request, dtoOptions, user).ConfigureAwait(false); + var result = GetQueryResult(request, dtoOptions, user); if (result == null) { @@ -134,7 +134,7 @@ namespace MediaBrowser.Api.UserLibrary /// /// Gets the items to serialize. /// - private async Task> GetQueryResult(GetItems request, DtoOptions dtoOptions, User user) + private QueryResult GetQueryResult(GetItems request, DtoOptions dtoOptions, User user) { var item = string.IsNullOrEmpty(request.ParentId) ? null : @@ -169,14 +169,14 @@ namespace MediaBrowser.Api.UserLibrary if (request.Recursive || !string.IsNullOrEmpty(request.Ids) || user == null) { - return await folder.GetItems(GetItemsQuery(request, dtoOptions, user)).ConfigureAwait(false); + return folder.GetItems(GetItemsQuery(request, dtoOptions, user)); } var userRoot = item as UserRootFolder; if (userRoot == null) { - return await folder.GetItems(GetItemsQuery(request, dtoOptions, user)).ConfigureAwait(false); + return folder.GetItems(GetItemsQuery(request, dtoOptions, user)); } IEnumerable items = folder.GetChildren(user, true); diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index c4cc90955..acbbde769 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -427,7 +427,7 @@ namespace MediaBrowser.Api.UserLibrary await item.MarkUnplayed(user).ConfigureAwait(false); } - return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false); + return _userDataRepository.GetUserDataDto(item, user); } } } \ No newline at end of file diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index 90db9348d..3b638208b 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -11,7 +11,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -542,7 +541,7 @@ namespace MediaBrowser.Api.UserLibrary await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false); - return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false); + return _userDataRepository.GetUserDataDto(item, user); } /// @@ -587,7 +586,7 @@ namespace MediaBrowser.Api.UserLibrary await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false); - return await _userDataRepository.GetUserDataDto(item, user).ConfigureAwait(false); + return _userDataRepository.GetUserDataDto(item, user); } } } diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs index 89953c2bd..3ed5166a4 100644 --- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs +++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Api.UserLibrary return ToOptimizedResult(result); } - public async Task Get(GetGroupingOptions request) + public object Get(GetGroupingOptions request) { var user = _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs index f7b83f23b..729b50c1f 100644 --- a/MediaBrowser.Api/VideosService.cs +++ b/MediaBrowser.Api/VideosService.cs @@ -9,7 +9,7 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Common/IO/ProgressStream.cs b/MediaBrowser.Common/IO/ProgressStream.cs deleted file mode 100644 index 468b3d345..000000000 --- a/MediaBrowser.Common/IO/ProgressStream.cs +++ /dev/null @@ -1,210 +0,0 @@ -using System; -using System.IO; - -namespace MediaBrowser.Common.IO -{ - /// - /// Measures progress when reading from a stream or writing to one - /// - public class ProgressStream : Stream - { - /// - /// Gets the base stream. - /// - /// The base stream. - public Stream BaseStream { get; private set; } - - /// - /// Gets or sets the bytes processed. - /// - /// The bytes processed. - private long BytesProcessed { get; set; } - /// - /// Gets or sets the length of the write. - /// - /// The length of the write. - private long WriteLength { get; set; } - - /// - /// Gets or sets the length of the read. - /// - /// The length of the read. - private long? ReadLength { get; set; } - - /// - /// Gets or sets the progress action. - /// - /// The progress action. - private Action ProgressAction { get; set; } - - /// - /// Creates the read progress stream. - /// - /// The base stream. - /// The progress action. - /// Length of the read. - /// ProgressStream. - public static ProgressStream CreateReadProgressStream(Stream baseStream, Action progressAction, long? readLength = null) - { - return new ProgressStream - { - BaseStream = baseStream, - ProgressAction = progressAction, - ReadLength = readLength - }; - } - - /// - /// Creates the write progress stream. - /// - /// The base stream. - /// The progress action. - /// Length of the write. - /// ProgressStream. - public static ProgressStream CreateWriteProgressStream(Stream baseStream, Action progressAction, long writeLength) - { - return new ProgressStream - { - BaseStream = baseStream, - ProgressAction = progressAction, - WriteLength = writeLength - }; - } - - /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports reading. - /// - /// true if this instance can read; otherwise, false. - /// true if the stream supports reading; otherwise, false. - public override bool CanRead - { - get { return BaseStream.CanRead; } - } - - /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking. - /// - /// true if this instance can seek; otherwise, false. - /// true if the stream supports seeking; otherwise, false. - public override bool CanSeek - { - get { return BaseStream.CanSeek; } - } - - /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports writing. - /// - /// true if this instance can write; otherwise, false. - /// true if the stream supports writing; otherwise, false. - public override bool CanWrite - { - get { return BaseStream.CanWrite; } - } - - /// - /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. - /// - public override void Flush() - { - BaseStream.Flush(); - } - - /// - /// When overridden in a derived class, gets the length in bytes of the stream. - /// - /// The length. - /// A long value representing the length of the stream in bytes. - public override long Length - { - get { return BaseStream.Length; } - } - - /// - /// When overridden in a derived class, gets or sets the position within the current stream. - /// - /// The position. - /// The current position within the stream. - public override long Position - { - get { return BaseStream.Position; } - set - { - BaseStream.Position = value; - } - } - - /// - /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. - public override int Read(byte[] buffer, int offset, int count) - { - var read = BaseStream.Read(buffer, offset, count); - - BytesProcessed += read; - - double percent = BytesProcessed; - percent /= ReadLength ?? BaseStream.Length; - percent *= 100; - - ProgressAction(percent); - - return read; - } - - /// - /// When overridden in a derived class, sets the position within the current stream. - /// - /// A byte offset relative to the parameter. - /// A value of type indicating the reference point used to obtain the new position. - /// The new position within the current stream. - public override long Seek(long offset, SeekOrigin origin) - { - return BaseStream.Seek(offset, origin); - } - - /// - /// When overridden in a derived class, sets the length of the current stream. - /// - /// The desired length of the current stream in bytes. - public override void SetLength(long value) - { - BaseStream.SetLength(value); - } - - /// - /// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// - /// An array of bytes. This method copies bytes from to the current stream. - /// The zero-based byte offset in at which to begin copying bytes to the current stream. - /// The number of bytes to be written to the current stream. - public override void Write(byte[] buffer, int offset, int count) - { - BaseStream.Write(buffer, offset, count); - - BytesProcessed += count; - - double percent = BytesProcessed; - percent /= WriteLength; - percent *= 100; - - ProgressAction(percent); - } - - /// - /// Releases the unmanaged resources used by the and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected override void Dispose(bool disposing) - { - if (disposing) - { - BaseStream.Dispose(); - } - base.Dispose(disposing); - } - } -} diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index e89d47394..b24975dba 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -47,7 +47,6 @@ - @@ -76,6 +75,7 @@ + diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index a2590dec7..35c2ea1aa 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -38,12 +38,12 @@ namespace MediaBrowser.Controller.Channels set { } } - protected override async Task> GetItemsInternal(InternalItemsQuery query) + protected override QueryResult GetItemsInternal(InternalItemsQuery query) { try { // Don't blow up here because it could cause parent screens with other content to fail - return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery + return ChannelManager.GetChannelItemsInternal(new ChannelItemQuery { ChannelId = Id.ToString("N"), Limit = query.Limit, @@ -52,7 +52,7 @@ namespace MediaBrowser.Controller.Channels SortBy = query.SortBy, SortOrder = query.SortOrder - }, new Progress(), CancellationToken.None); + }, new Progress(), CancellationToken.None).Result; } catch { diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 792744628..824bdf8ff 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -110,7 +110,7 @@ namespace MediaBrowser.Controller.Channels /// The item. /// The cancellation token. /// Task{IEnumerable{MediaSourceInfo}}. - Task> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken); + IEnumerable GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken); /// /// Gets the channel folder. diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index a1de23c93..fe8ac0919 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 92d8d95bc..873ac3104 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -209,7 +209,7 @@ namespace MediaBrowser.Controller.Entities.Audio if (SourceType == SourceType.Channel) { var sources = ChannelManager.GetStaticMediaSources(this, CancellationToken.None) - .Result.ToList(); + .ToList(); if (sources.Count > 0) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 1fe7dd3f6..a46ac9135 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -21,7 +21,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.IO; @@ -2253,7 +2253,7 @@ namespace MediaBrowser.Controller.Entities return path; } - public virtual Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields) + public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields) { if (RunTimeTicks.HasValue) { @@ -2269,8 +2269,6 @@ namespace MediaBrowser.Controller.Entities } } } - - return Task.FromResult(true); } protected Task RefreshMetadataForOwnedItem(BaseItem ownedItem, bool copyTitleMetadata, MetadataRefreshOptions options, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 24474ba55..0a5faa727 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -7,7 +7,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Extensions; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b602be9ea..28856b753 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -10,7 +10,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities.Audio; @@ -698,7 +698,7 @@ namespace MediaBrowser.Controller.Entities EnableImages = false } - }).Result; + }); return result.TotalRecordCount; } @@ -717,7 +717,7 @@ namespace MediaBrowser.Controller.Entities EnableImages = false } - }).Result.TotalRecordCount; + }).TotalRecordCount; } public QueryResult QueryRecursive(InternalItemsQuery query) @@ -925,7 +925,7 @@ namespace MediaBrowser.Controller.Entities return false; } - public Task> GetItems(InternalItemsQuery query) + public QueryResult GetItems(InternalItemsQuery query) { if (query.ItemIds.Length > 0) { @@ -938,20 +938,20 @@ namespace MediaBrowser.Controller.Entities // Try to preserve order result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray(); } - return Task.FromResult(result); + return result; } return GetItemsInternal(query); } - protected virtual async Task> GetItemsInternal(InternalItemsQuery query) + protected virtual QueryResult GetItemsInternal(InternalItemsQuery query) { if (SourceType == SourceType.Channel) { try { // Don't blow up here because it could cause parent screens with other content to fail - return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery + return ChannelManager.GetChannelItemsInternal(new ChannelItemQuery { ChannelId = ChannelId, FolderId = Id.ToString("N"), @@ -961,7 +961,7 @@ namespace MediaBrowser.Controller.Entities SortBy = query.SortBy, SortOrder = query.SortOrder - }, new Progress(), CancellationToken.None); + }, new Progress(), CancellationToken.None).Result; } catch { @@ -1362,7 +1362,7 @@ namespace MediaBrowser.Controller.Entities query.IsVirtualItem = false; } - var itemsResult = await GetItems(query).ConfigureAwait(false); + var itemsResult = GetItems(query); // Sweep through recursively and update status var tasks = itemsResult.Items.Select(c => c.MarkPlayed(user, datePlayed, resetPosition)); @@ -1377,14 +1377,14 @@ namespace MediaBrowser.Controller.Entities /// Task. public override async Task MarkUnplayed(User user) { - var itemsResult = await GetItems(new InternalItemsQuery + var itemsResult = GetItems(new InternalItemsQuery { User = user, Recursive = true, IsFolder = false, EnableTotalRecordCount = false - }).ConfigureAwait(false); + }); // Sweep through recursively and update status var tasks = itemsResult.Items.Select(c => c.MarkUnplayed(user)); @@ -1401,7 +1401,7 @@ namespace MediaBrowser.Controller.Entities IsVirtualItem = false, EnableTotalRecordCount = false - }).Result; + }); return itemsResult.Items .All(i => i.IsPlayed(user)); @@ -1452,7 +1452,7 @@ namespace MediaBrowser.Controller.Entities } } - public override async Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields) + public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields) { if (!SupportsUserDataFromChildren) { @@ -1469,7 +1469,7 @@ namespace MediaBrowser.Controller.Entities if (SupportsPlayedStatus) { - var unplayedQueryResult = await GetItems(new InternalItemsQuery(user) + var unplayedQueryResult = GetItems(new InternalItemsQuery(user) { Recursive = true, IsFolder = false, @@ -1482,7 +1482,7 @@ namespace MediaBrowser.Controller.Entities EnableImages = false } - }).ConfigureAwait(false); + }); double unplayedCount = unplayedQueryResult.TotalRecordCount; diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index 2104bee09..e2b3c0777 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -3,7 +3,7 @@ using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs index 0b3b7dc8d..0029947ee 100644 --- a/MediaBrowser.Controller/Entities/IHasUserData.cs +++ b/MediaBrowser.Controller/Entities/IHasUserData.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities /// /// Fills the user data dto values. /// - Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields); + void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, List fields); bool EnableRememberingTrackSelections { get; } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index c2a01f4ff..8a5b726e2 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Providers; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 4a3c9c081..17494eb08 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -150,7 +150,7 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } - protected override Task> GetItemsInternal(InternalItemsQuery query) + protected override QueryResult GetItemsInternal(InternalItemsQuery query) { if (query.User == null) { @@ -165,7 +165,7 @@ namespace MediaBrowser.Controller.Entities.TV var result = PostFilterAndSort(items, query, false, false); - return Task.FromResult(result); + return result; } /// diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 45dbed216..c54f93f11 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -289,7 +289,7 @@ namespace MediaBrowser.Controller.Entities.TV } } - protected override Task> GetItemsInternal(InternalItemsQuery query) + protected override QueryResult GetItemsInternal(InternalItemsQuery query) { if (query.User == null) { @@ -313,12 +313,12 @@ namespace MediaBrowser.Controller.Entities.TV query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }; } query.IsVirtualItem = false; - return Task.FromResult(LibraryManager.GetItemsResult(query)); + return LibraryManager.GetItemsResult(query); } SetSeasonQueryOptions(query, user); - return Task.FromResult(LibraryManager.GetItemsResult(query)); + return LibraryManager.GetItemsResult(query); } public IEnumerable GetEpisodes(User user, DtoOptions options) diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index b602990ac..c93c81401 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -50,23 +50,23 @@ namespace MediaBrowser.Controller.Entities } } - protected override async Task> GetItemsInternal(InternalItemsQuery query) + protected override QueryResult GetItemsInternal(InternalItemsQuery query) { if (query.Recursive) { return QueryRecursive(query); } - var result = await UserViewManager.GetUserViews(new UserViewQuery + var result = UserViewManager.GetUserViews(new UserViewQuery { UserId = query.User.Id.ToString("N"), PresetViews = query.PresetViews - }, CancellationToken.None).ConfigureAwait(false); + }, CancellationToken.None).Result; var user = query.User; Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - + return PostFilterAndSort(result.Where(filter), query, true, true); } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index ac843d5fb..27be696eb 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Entities return GetChildren(user, true).Count(); } - protected override Task> GetItemsInternal(InternalItemsQuery query) + protected override QueryResult GetItemsInternal(InternalItemsQuery query) { var parent = this as Folder; @@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Entities } return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager, PlaylistManager) - .GetUserItems(parent, this, ViewType, query); + .GetUserItems(parent, this, ViewType, query).Result; } public override IEnumerable GetChildren(User user, bool includeLinkedChildren) @@ -79,7 +79,7 @@ namespace MediaBrowser.Controller.Entities EnableTotalRecordCount = false, DtoOptions = new DtoOptions(true) - }).Result; + }); return result.Items; } @@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Entities DtoOptions = query.DtoOptions - }).Result; + }); return result.Items.Where(i => UserViewBuilder.FilterItem(i, query)); } diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index b5ece06a6..91e24caeb 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -142,7 +142,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(user.RootFolder.GetChildren(user, true), queryParent, query); case CollectionType.Playlists: - return await GetPlaylistsView(queryParent, user, query).ConfigureAwait(false); + return GetPlaylistsView(queryParent, user, query); case CollectionType.BoxSets: return GetBoxsetView(queryParent, user, query); @@ -181,7 +181,7 @@ namespace MediaBrowser.Controller.Entities return await GetMovieGenres(queryParent, user, query).ConfigureAwait(false); case SpecialFolder.MovieGenre: - return await GetMovieGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false); + return GetMovieGenreItems(queryParent, displayParent, user, query); case SpecialFolder.MovieResume: return GetMovieResume(queryParent, user, query); @@ -424,13 +424,6 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private async Task> FindPlaylists(Folder parent, User user, InternalItemsQuery query) - { - var list = _playlistManager.GetPlaylists(user.Id.ToString("N")); - - return GetResult(list, parent, query); - } - private int GetSpecialItemsLimit() { return 50; @@ -583,7 +576,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(genres, parent, query); } - private async Task> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) + private QueryResult GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) { query.Recursive = true; query.Parent = queryParent; @@ -595,7 +588,7 @@ namespace MediaBrowser.Controller.Entities return _libraryManager.GetItemsResult(query); } - private async Task> GetPlaylistsView(Folder parent, User user, InternalItemsQuery query) + private QueryResult GetPlaylistsView(Folder parent, User user, InternalItemsQuery query) { return GetResult(_playlistManager.GetPlaylists(user.Id.ToString("N")), parent, query); } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index a02b6957f..fb31d9a47 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -11,7 +11,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -552,7 +552,7 @@ namespace MediaBrowser.Controller.Entities if (SourceType == SourceType.Channel) { var sources = ChannelManager.GetStaticMediaSources(this, CancellationToken.None) - .Result.ToList(); + .ToList(); if (sources.Count > 0) { diff --git a/MediaBrowser.Controller/IO/FileData.cs b/MediaBrowser.Controller/IO/FileData.cs index d40829d44..97b778d0c 100644 --- a/MediaBrowser.Controller/IO/FileData.cs +++ b/MediaBrowser.Controller/IO/FileData.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.IO diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 7dcc207db..3f6b5a806 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -10,7 +10,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 5940c7e29..e9954545e 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -38,9 +38,9 @@ namespace MediaBrowser.Controller.Library /// /// Gets the user data dto. /// - Task GetUserDataDto(IHasUserData item, User user); + UserItemDataDto GetUserDataDto(IHasUserData item, User user); - Task GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List fields); + UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List fields); /// /// Get all user data for the given user diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 3aa4d4ee2..3ddda81cd 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index bac9807a9..10d7b9a7e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -124,7 +124,7 @@ namespace MediaBrowser.Controller.MediaEncoding Task Init(); - Task UpdateEncoderPath(string path, string pathType); + void UpdateEncoderPath(string path, string pathType); bool SupportsEncoder(string encoder); void SetLogFilename(string name); diff --git a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs index 0b1ca08e5..d5c85197f 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; namespace MediaBrowser.Controller.MediaEncoding diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index 9f295c71d..7b431f69a 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs index 62c13fbb5..3064cbf10 100644 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; namespace MediaBrowser.Controller.Net diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 73c3b9a25..790e8e824 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Controller.Playlists public override IEnumerable GetChildren(User user, bool includeLinkedChildren) { - return GetPlayableItems(user, new DtoOptions(true)).Result; + return GetPlayableItems(user, new DtoOptions(true)); } protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) @@ -92,7 +92,7 @@ namespace MediaBrowser.Controller.Playlists public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { - var items = GetPlayableItems(user, query.DtoOptions).Result; + var items = GetPlayableItems(user, query.DtoOptions); if (query != null) { @@ -107,12 +107,12 @@ namespace MediaBrowser.Controller.Playlists return GetLinkedChildrenInfos(); } - private Task> GetPlayableItems(User user, DtoOptions options) + private IEnumerable GetPlayableItems(User user, DtoOptions options) { return GetPlaylistItems(MediaType, base.GetChildren(user, true), user, options); } - public static async Task> GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, User user, DtoOptions options) + public static IEnumerable GetPlaylistItems(string playlistMediaType, IEnumerable inputItems, User user, DtoOptions options) { if (user != null) { @@ -123,14 +123,14 @@ namespace MediaBrowser.Controller.Playlists foreach (var item in inputItems) { - var playlistItems = await GetPlaylistItems(item, user, playlistMediaType, options).ConfigureAwait(false); + var playlistItems = GetPlaylistItems(item, user, playlistMediaType, options); list.AddRange(playlistItems); } return list; } - private static async Task> GetPlaylistItems(BaseItem item, User user, string mediaType, DtoOptions options) + private static IEnumerable GetPlaylistItems(BaseItem item, User user, string mediaType, DtoOptions options) { var musicGenre = item as MusicGenre; if (musicGenre != null) @@ -173,7 +173,7 @@ namespace MediaBrowser.Controller.Playlists DtoOptions = options }; - var itemsResult = await folder.GetItems(query).ConfigureAwait(false); + var itemsResult = folder.GetItems(query); var items = itemsResult.Items; return items; diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 62db007b9..3d1af2afa 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -4,7 +4,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index f78d9cd6a..1b203f32c 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Providers/LocalImageInfo.cs b/MediaBrowser.Controller/Providers/LocalImageInfo.cs index 63651fce8..5e6efe9f6 100644 --- a/MediaBrowser.Controller/Providers/LocalImageInfo.cs +++ b/MediaBrowser.Controller/Providers/LocalImageInfo.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 7d9dab92b..ed1e4325d 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -1,5 +1,5 @@ using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.Controller/Resolvers/IItemResolver.cs b/MediaBrowser.Controller/Resolvers/IItemResolver.cs index fcb162b9e..3af5d5f7f 100644 --- a/MediaBrowser.Controller/Resolvers/IItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/IItemResolver.cs @@ -2,7 +2,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs index 06372395e..25537193a 100644 --- a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs +++ b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs @@ -1,4 +1,4 @@ -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs index 50e9de727..9400cccf3 100644 --- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Providers; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs index d393b98d9..954e0c322 100644 --- a/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs @@ -1,7 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs index bd33dece8..fbb6b20f1 100644 --- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs @@ -6,7 +6,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs index 7e3a05683..83554f044 100644 --- a/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs index 8003803ea..47579f870 100644 --- a/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs @@ -4,7 +4,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using System.Collections.Generic; using System.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index f147f1d61..b449ad6e0 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -7,7 +7,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs index 69d799b18..6aba137eb 100644 --- a/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/EpisodeXmlParser.cs @@ -8,7 +8,7 @@ using System.Globalization; using System.IO; using System.Threading; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs index 88c51caaa..30576b531 100644 --- a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs @@ -4,7 +4,7 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs index fda8ea6d0..fc936f780 100644 --- a/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/EpisodeXmlProvider.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Logging; using System.Collections.Generic; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs index 45cd8eb93..0b596a5be 100644 --- a/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/FolderXmlProvider.cs @@ -1,6 +1,6 @@ using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs index 8054b1204..006376b41 100644 --- a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs @@ -1,6 +1,6 @@ using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs index 8ed18df64..3e7acc28d 100644 --- a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs @@ -4,7 +4,7 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs index 2d4059a1a..572fa7f4c 100644 --- a/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/MovieXmlProvider.cs @@ -4,7 +4,7 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs index e0bbb119f..f91e236f7 100644 --- a/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/MusicVideoXmlProvider.cs @@ -1,5 +1,5 @@ using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs index cd839f9cc..4d0495acb 100644 --- a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs @@ -4,7 +4,7 @@ using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs index ce006ef38..922005187 100644 --- a/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs @@ -1,6 +1,6 @@ using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs index 4a7149657..4212bf2c8 100644 --- a/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/VideoXmlProvider.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.Logging; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs index 8167f6002..214b44ae7 100644 --- a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs @@ -7,7 +7,7 @@ using System.IO; using System.Text; using System.Threading; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs index b51bd5b91..d5d878ef7 100644 --- a/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/FolderXmlSaver.cs @@ -10,8 +10,6 @@ using System.IO; using System.Text; using System.Threading; using System.Xml; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs index 5beab746d..16c67655a 100644 --- a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs +++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs @@ -2,7 +2,7 @@ using MediaBrowser.Model.Configuration; using System.Collections.Generic; using System.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs index 42048ab9e..1b5b4b4e4 100644 --- a/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs +++ b/MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; + using MediaBrowser.Common.Net; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index c58a18b0f..280b01ee2 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -252,7 +252,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - public async Task UpdateEncoderPath(string path, string pathType) + public void UpdateEncoderPath(string path, string pathType) { if (_hasExternalEncoder) { @@ -786,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder timeoutMs = DefaultImageExtractionTimeoutMs; } - ranToCompletion = process.WaitForExit(timeoutMs); + ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false); if (!ranToCompletion) { @@ -892,7 +892,7 @@ namespace MediaBrowser.MediaEncoding.Encoder while (isResponsive) { - if (process.WaitForExit(30000)) + if (await process.WaitForExitAsync(30000).ConfigureAwait(false)) { ranToCompletion = true; break; diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 6270b87c6..1e91a8198 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Text; using System.Xml; using MediaBrowser.Model.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 1e983ca15..f8f95684d 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - private async Task ConvertSubtitles(Stream stream, + private Stream ConvertSubtitles(Stream stream, string inputFormat, string outputFormat, long startTimeTicks, @@ -166,7 +166,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles using (var stream = subtitle.Item1) { - return await ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken).ConfigureAwait(false); + return ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken); } } @@ -445,7 +445,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw; } - var ranToCompletion = process.WaitForExit(60000); + var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false); if (!ranToCompletion) { @@ -575,7 +575,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw; } - var ranToCompletion = process.WaitForExit(300000); + var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false); if (!ranToCompletion) { diff --git a/MediaBrowser.Model/Diagnostics/IProcess.cs b/MediaBrowser.Model/Diagnostics/IProcess.cs index ab0b0cfcf..7cd26af00 100644 --- a/MediaBrowser.Model/Diagnostics/IProcess.cs +++ b/MediaBrowser.Model/Diagnostics/IProcess.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Tasks; namespace MediaBrowser.Model.Diagnostics { @@ -9,6 +10,7 @@ namespace MediaBrowser.Model.Diagnostics void Kill(); bool WaitForExit(int timeMs); + Task WaitForExitAsync(int timeMs); int ExitCode { get; } void Start(); StreamWriter StandardInput { get; } diff --git a/MediaBrowser.Model/Net/IAcceptSocket.cs b/MediaBrowser.Model/Net/IAcceptSocket.cs index 4262e2390..2b5d33dce 100644 --- a/MediaBrowser.Model/Net/IAcceptSocket.cs +++ b/MediaBrowser.Model/Net/IAcceptSocket.cs @@ -1,6 +1,4 @@ using System; -using System.Threading; -using System.Threading.Tasks; namespace MediaBrowser.Model.Net { @@ -15,7 +13,8 @@ namespace MediaBrowser.Model.Net void Bind(IpEndPointInfo endpoint); void Connect(IpEndPointInfo endPoint); void StartAccept(Action onAccept, Func isClosed); - Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken); + IAsyncResult BeginSendFile(string path, byte[] preBuffer, byte[] postBuffer, AsyncCallback callback, object state); + void EndSendFile(IAsyncResult result); } public class SocketCreateException : Exception diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs index 1cf6c7cc7..7ad08f106 100644 --- a/MediaBrowser.Model/Net/ISocket.cs +++ b/MediaBrowser.Model/Net/ISocket.cs @@ -14,11 +14,6 @@ namespace MediaBrowser.Model.Net { IpAddressInfo LocalIPAddress { get; } - /// - /// Waits for and returns the next UDP message sent to this socket (uni or multicast). - /// - /// - Task ReceiveAsync(CancellationToken cancellationToken); Task ReceiveAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback); diff --git a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs index 696619a8c..7cce85105 100644 --- a/MediaBrowser.Providers/Books/AudioBookMetadataService.cs +++ b/MediaBrowser.Providers/Books/AudioBookMetadataService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs b/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs index 86b2cf1b1..219f95799 100644 --- a/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs +++ b/MediaBrowser.Providers/Books/AudioPodcastMetadataService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Books/BookMetadataService.cs b/MediaBrowser.Providers/Books/BookMetadataService.cs index ccc69eb62..ae7e734cc 100644 --- a/MediaBrowser.Providers/Books/BookMetadataService.cs +++ b/MediaBrowser.Providers/Books/BookMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index a625b93b8..b391ce4d3 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -9,7 +9,7 @@ using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -17,9 +17,9 @@ namespace MediaBrowser.Providers.BoxSets { public class BoxSetMetadataService : MetadataService { - protected override async Task BeforeSave(BoxSet item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected override ItemUpdateType BeforeSave(BoxSet item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); + var updateType = base.BeforeSave(item, isFullRefresh, currentUpdateType); if (isFullRefresh || currentUpdateType > ItemUpdateType.None) { diff --git a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs index 6175c3622..e271772cc 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -16,7 +16,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs index c2a6c07f9..8a3da5bf4 100644 --- a/MediaBrowser.Providers/Channels/ChannelMetadataService.cs +++ b/MediaBrowser.Providers/Channels/ChannelMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs index c6013a94d..dc0fda72e 100644 --- a/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/CollectionFolderMetadataService.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; diff --git a/MediaBrowser.Providers/Folders/FolderMetadataService.cs b/MediaBrowser.Providers/Folders/FolderMetadataService.cs index 94125b29d..ff8d87e2b 100644 --- a/MediaBrowser.Providers/Folders/FolderMetadataService.cs +++ b/MediaBrowser.Providers/Folders/FolderMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs index b1410bfd9..06b62a98b 100644 --- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs +++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs index 180d36378..13d40b4d9 100644 --- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs +++ b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs index d6f61fa94..10f74629f 100644 --- a/MediaBrowser.Providers/Games/GameMetadataService.cs +++ b/MediaBrowser.Providers/Games/GameMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs index 5794e8c9b..ca33563fa 100644 --- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs +++ b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Genres/GenreMetadataService.cs b/MediaBrowser.Providers/Genres/GenreMetadataService.cs index 39f9354db..a695fb372 100644 --- a/MediaBrowser.Providers/Genres/GenreMetadataService.cs +++ b/MediaBrowser.Providers/Genres/GenreMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs index df4a03cdb..f4749c37d 100644 --- a/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs +++ b/MediaBrowser.Providers/LiveTv/AudioRecordingService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs index 7b5065986..8012021ab 100644 --- a/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ChannelMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs index eaacc41fa..f203aa8c6 100644 --- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs +++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs index a8df3c88b..528e9a5ec 100644 --- a/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs +++ b/MediaBrowser.Providers/LiveTv/VideoRecordingService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 91c366df5..dc6c7e43f 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -1,5 +1,5 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 31cdc164c..39715a449 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -15,7 +15,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 59a2278a1..edca5e7d6 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -53,8 +53,8 @@ namespace MediaBrowser.Providers.Manager requiresRefresh = item.RequiresRefresh(); } - if (!requiresRefresh && - libraryOptions.AutomaticRefreshIntervalDays > 0 && + if (!requiresRefresh && + libraryOptions.AutomaticRefreshIntervalDays > 0 && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= libraryOptions.AutomaticRefreshIntervalDays) { requiresRefresh = true; @@ -142,7 +142,7 @@ namespace MediaBrowser.Providers.Manager } } - var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh, updateType).ConfigureAwait(false); + var beforeSaveResult = BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh, updateType); updateType = updateType | beforeSaveResult; if (item.LocationType == LocationType.FileSystem) @@ -281,7 +281,7 @@ namespace MediaBrowser.Providers.Manager /// if set to true [is full refresh]. /// Type of the current update. /// ItemUpdateType. - protected virtual async Task BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected virtual ItemUpdateType BeforeSave(TItemType item, bool isFullRefresh, ItemUpdateType currentUpdateType) { var updateType = ItemUpdateType.None; @@ -368,7 +368,7 @@ namespace MediaBrowser.Providers.Manager // Run all if either of these flags are true var runAllProviders = options.ReplaceAllMetadata || - metadataRefreshMode == MetadataRefreshMode.FullRefresh || + metadataRefreshMode == MetadataRefreshMode.FullRefresh || (isFirstRefresh && metadataRefreshMode >= MetadataRefreshMode.Default) || (requiresRefresh && metadataRefreshMode >= MetadataRefreshMode.Default); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 131bf50c3..f80b99c7a 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -20,7 +20,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -556,6 +556,7 @@ namespace MediaBrowser.Providers.Manager new MetadataOptions(); } + private Task _completedTask = Task.FromResult(true); /// /// Saves the metadata. /// @@ -564,7 +565,8 @@ namespace MediaBrowser.Providers.Manager /// Task. public Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType) { - return SaveMetadata(item, updateType, _savers); + SaveMetadata(item, updateType, _savers); + return _completedTask; } /// @@ -576,7 +578,8 @@ namespace MediaBrowser.Providers.Manager /// Task. public Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable savers) { - return SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); + SaveMetadata(item, updateType, _savers.Where(i => savers.Contains(i.Name, StringComparer.OrdinalIgnoreCase))); + return _completedTask; } /// @@ -586,7 +589,7 @@ namespace MediaBrowser.Providers.Manager /// Type of the update. /// The savers. /// Task. - private async Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable savers) + private void SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable savers) { foreach (var saver in savers.Where(i => IsSaverEnabledForItem(i, item, updateType, false))) { diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index c686e1d2e..eaf3505d1 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -25,7 +25,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 84d8d20ad..ba24bd600 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -19,7 +19,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Controller.LiveTv; diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 670215479..6a1af9272 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -13,7 +13,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Extensions; diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index d6aef5d1c..fe190afb4 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -18,7 +18,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.IO; using MediaBrowser.Common; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Net; diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 2187d6df1..333d289ec 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs index e5dbba902..bba40608c 100644 --- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs +++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs @@ -9,7 +9,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -17,9 +16,9 @@ namespace MediaBrowser.Providers.Music { public class AlbumMetadataService : MetadataService { - protected override async Task BeforeSave(MusicAlbum item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected override ItemUpdateType BeforeSave(MusicAlbum item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); + var updateType = base.BeforeSave(item, isFullRefresh, currentUpdateType); if (isFullRefresh || currentUpdateType > ItemUpdateType.None) { diff --git a/MediaBrowser.Providers/Music/ArtistMetadataService.cs b/MediaBrowser.Providers/Music/ArtistMetadataService.cs index 1bd427ac9..d4e580871 100644 --- a/MediaBrowser.Providers/Music/ArtistMetadataService.cs +++ b/MediaBrowser.Providers/Music/ArtistMetadataService.cs @@ -9,17 +9,15 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.Music { public class ArtistMetadataService : MetadataService { - protected override async Task BeforeSave(MusicArtist item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected override ItemUpdateType BeforeSave(MusicArtist item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); + var updateType = base.BeforeSave(item, isFullRefresh, currentUpdateType); if (isFullRefresh || currentUpdateType > ItemUpdateType.None) { diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs index 6d9b20689..cd6b0b827 100644 --- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs @@ -13,7 +13,7 @@ using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -40,9 +40,9 @@ namespace MediaBrowser.Providers.Music Current = this; } - public async Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) + public Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) { - return new List(); + return Task.FromResult((IEnumerable)new List()); } public async Task> GetMetadata(AlbumInfo info, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs index c960e59a3..d8a7dbc04 100644 --- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs @@ -12,7 +12,7 @@ using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -39,9 +39,9 @@ namespace MediaBrowser.Providers.Music Current = this; } - public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) + public Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) { - return new List(); + return Task.FromResult((IEnumerable)new List()); } public async Task> GetMetadata(ArtistInfo info, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Music/AudioMetadataService.cs b/MediaBrowser.Providers/Music/AudioMetadataService.cs index faa8bb3ad..4d791be01 100644 --- a/MediaBrowser.Providers/Music/AudioMetadataService.cs +++ b/MediaBrowser.Providers/Music/AudioMetadataService.cs @@ -7,8 +7,6 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.Music diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index d22929664..5700b2386 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -14,7 +14,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index 977f81414..eefebed29 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -17,7 +17,7 @@ using System.Net; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; diff --git a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs index 88689dd5a..50fb1de1f 100644 --- a/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs +++ b/MediaBrowser.Providers/Music/MovieDbMusicVideoProvider.cs @@ -17,9 +17,9 @@ namespace MediaBrowser.Providers.Music return MovieDbProvider.Current.GetItemMetadata(info, cancellationToken); } - public async Task> GetSearchResults(MusicVideoInfo searchInfo, CancellationToken cancellationToken) + public Task> GetSearchResults(MusicVideoInfo searchInfo, CancellationToken cancellationToken) { - return new List(); + return Task.FromResult((IEnumerable)new List()); } public string Name diff --git a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs index f46b6b128..b8f6e2c63 100644 --- a/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs +++ b/MediaBrowser.Providers/Music/MusicVideoMetadataService.cs @@ -7,7 +7,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs index f1ffd09db..ba059bd7b 100644 --- a/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs +++ b/MediaBrowser.Providers/MusicGenres/MusicGenreMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs index 812f0443e..98a746053 100644 --- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs @@ -12,7 +12,7 @@ using MediaBrowser.Model.Serialization; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; namespace MediaBrowser.Providers.Omdb diff --git a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs index f9d19b6be..02cb3dbf3 100644 --- a/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbItemProvider.cs @@ -125,7 +125,7 @@ namespace MediaBrowser.Providers.Omdb } } - var url = await OmdbProvider.GetOmdbUrl(urlQuery, cancellationToken).ConfigureAwait(false); + var url = OmdbProvider.GetOmdbUrl(urlQuery, cancellationToken); using (var stream = await OmdbProvider.GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index dd3ba23db..41ff71070 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -265,7 +265,7 @@ namespace MediaBrowser.Providers.Omdb return false; } - public static async Task GetOmdbUrl(string query, CancellationToken cancellationToken) + public static string GetOmdbUrl(string query, CancellationToken cancellationToken) { var url = "https://www.omdbapi.com?apikey=fe53f97e"; @@ -299,7 +299,7 @@ namespace MediaBrowser.Providers.Omdb } } - var url = await GetOmdbUrl(string.Format("i={0}&plot=full&tomatoes=true&r=json", imdbParam), cancellationToken).ConfigureAwait(false); + var url = GetOmdbUrl(string.Format("i={0}&plot=full&tomatoes=true&r=json", imdbParam), cancellationToken); using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { @@ -333,7 +333,7 @@ namespace MediaBrowser.Providers.Omdb } } - var url = await GetOmdbUrl(string.Format("i={0}&season={1}&detail=full", imdbParam, seasonId), cancellationToken).ConfigureAwait(false); + var url = GetOmdbUrl(string.Format("i={0}&season={1}&detail=full", imdbParam, seasonId), cancellationToken); using (var stream = await GetOmdbResponse(_httpClient, url, cancellationToken).ConfigureAwait(false)) { diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 19b8f292c..986c4b4a9 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -16,7 +16,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.Providers/People/PersonMetadataService.cs b/MediaBrowser.Providers/People/PersonMetadataService.cs index a306212ff..5d70fc1d6 100644 --- a/MediaBrowser.Providers/People/PersonMetadataService.cs +++ b/MediaBrowser.Providers/People/PersonMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs index b64b2f24e..85b9dafd4 100644 --- a/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs +++ b/MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs index 617a510b8..909d359b9 100644 --- a/MediaBrowser.Providers/Photos/PhotoMetadataService.cs +++ b/MediaBrowser.Providers/Photos/PhotoMetadataService.cs @@ -6,8 +6,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.Photos diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs index cfdba0fb2..235fd8c8a 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Studios/StudioMetadataService.cs b/MediaBrowser.Providers/Studios/StudioMetadataService.cs index c773b7896..ef5ced3e2 100644 --- a/MediaBrowser.Providers/Studios/StudioMetadataService.cs +++ b/MediaBrowser.Providers/Studios/StudioMetadataService.cs @@ -6,8 +6,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.Studios diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 1cf965e02..b4c6aa02c 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -16,7 +16,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs index 279447a18..3b2d674a6 100644 --- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs +++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs @@ -8,7 +8,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs index bef4d8815..8adb6d4d2 100644 --- a/MediaBrowser.Providers/TV/EpisodeMetadataService.cs +++ b/MediaBrowser.Providers/TV/EpisodeMetadataService.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -16,9 +16,9 @@ namespace MediaBrowser.Providers.TV { public class EpisodeMetadataService : MetadataService { - protected override async Task BeforeSave(Episode item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected override ItemUpdateType BeforeSave(Episode item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); + var updateType = base.BeforeSave(item, isFullRefresh, currentUpdateType); var seriesName = item.FindSeriesName(); if (!string.Equals(item.SeriesName, seriesName, StringComparison.Ordinal)) diff --git a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs index f1fc2c9f3..b9f010bb6 100644 --- a/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArt/FanArtSeasonProvider.cs @@ -18,7 +18,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs index 35178e1fe..644e9cbb5 100644 --- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs @@ -20,7 +20,7 @@ using System.Net; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index 5b9e5d5eb..da5a1f2d1 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -13,7 +13,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs index f73244cdf..daf493ad9 100644 --- a/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs @@ -12,7 +12,7 @@ using MediaBrowser.Providers.Omdb; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; namespace MediaBrowser.Providers.TV diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs index 74c8b4ec3..1b4e3f44f 100644 --- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs @@ -9,7 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; @@ -17,9 +17,9 @@ namespace MediaBrowser.Providers.TV { public class SeasonMetadataService : MetadataService { - protected override async Task BeforeSave(Season item, bool isFullRefresh, ItemUpdateType currentUpdateType) + protected override ItemUpdateType BeforeSave(Season item, bool isFullRefresh, ItemUpdateType currentUpdateType) { - var updateType = await base.BeforeSave(item, isFullRefresh, currentUpdateType).ConfigureAwait(false); + var updateType = base.BeforeSave(item, isFullRefresh, currentUpdateType); if (item.IndexNumber.HasValue && item.IndexNumber.Value == 0) { diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index 0d89e307f..7559a15de 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -9,7 +9,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs index 952c4f934..854f9f06b 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeImageProvider.cs @@ -14,7 +14,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs index d2191e1a6..1938f7ff0 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs @@ -16,7 +16,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs index b2d70918c..5ca2d5518 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs @@ -10,7 +10,7 @@ using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs index f41e254ca..528ba3d0c 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs @@ -15,7 +15,7 @@ using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs index 7bf926799..fe3d7d78c 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs @@ -17,7 +17,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Globalization; diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs index 030150e4d..48e50c2e1 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeImageProvider.cs @@ -12,8 +12,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.TV diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs index 24c2b507a..686bacfe1 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs @@ -16,7 +16,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; @@ -48,14 +48,14 @@ namespace MediaBrowser.Providers.TV Current = this; } - public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) + public Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) { var list = new List(); // The search query must either provide an episode number or date if (!searchInfo.IndexNumber.HasValue && !searchInfo.PremiereDate.HasValue) { - return list; + return Task.FromResult((IEnumerable)list); } if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds)) @@ -103,7 +103,7 @@ namespace MediaBrowser.Providers.TV } } - return list; + return Task.FromResult((IEnumerable)list); } public string Name diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs index 5fccb9e3c..9a457ba94 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs @@ -14,7 +14,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dto; using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs index daa6e78f5..395d419cf 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeasonImageProvider.cs @@ -16,8 +16,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs index 50bc6bc74..d7eea4226 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesImageProvider.cs @@ -16,7 +16,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.Providers/Users/UserMetadataService.cs b/MediaBrowser.Providers/Users/UserMetadataService.cs index 274d04efd..88df704d6 100644 --- a/MediaBrowser.Providers/Users/UserMetadataService.cs +++ b/MediaBrowser.Providers/Users/UserMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Providers/Videos/VideoMetadataService.cs b/MediaBrowser.Providers/Videos/VideoMetadataService.cs index 49f7e11ba..a07cc5949 100644 --- a/MediaBrowser.Providers/Videos/VideoMetadataService.cs +++ b/MediaBrowser.Providers/Videos/VideoMetadataService.cs @@ -6,8 +6,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.Providers.Videos diff --git a/MediaBrowser.Providers/Years/YearMetadataService.cs b/MediaBrowser.Providers/Years/YearMetadataService.cs index 72f8eb471..36c2fd1dd 100644 --- a/MediaBrowser.Providers/Years/YearMetadataService.cs +++ b/MediaBrowser.Providers/Years/YearMetadataService.cs @@ -6,7 +6,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs index 5dcb81736..57254eed4 100644 --- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs +++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs @@ -5,9 +5,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.IO; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Serialization; diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index 07773d846..bd16dc2e9 100644 --- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Playlists get { return MediaBrowser.Model.Entities.CollectionType.Playlists; } } - protected override Task> GetItemsInternal(InternalItemsQuery query) + protected override QueryResult GetItemsInternal(InternalItemsQuery query) { query.Recursive = false; return base.GetItemsInternal(query); diff --git a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs index c80ebda45..f56ceed89 100644 --- a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs @@ -5,7 +5,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.XbmcMetadata.Parsers; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs index 119dcf2f3..4fcc222f8 100644 --- a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs @@ -5,8 +5,6 @@ using MediaBrowser.Model.Logging; using MediaBrowser.XbmcMetadata.Parsers; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs index e5931cf25..4803004dd 100644 --- a/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/BaseNfoProvider.cs @@ -4,8 +4,6 @@ using MediaBrowser.XbmcMetadata.Savers; using System.IO; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.XbmcMetadata.Providers diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs index ff798c0f2..eeb55d8bc 100644 --- a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs @@ -6,7 +6,7 @@ using MediaBrowser.XbmcMetadata.Parsers; using MediaBrowser.XbmcMetadata.Savers; using System.Linq; using System.Threading; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs index 9deaa9745..3bc10f35b 100644 --- a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs @@ -6,8 +6,6 @@ using MediaBrowser.XbmcMetadata.Parsers; using System.Collections.Generic; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs index 75d85b295..031bdc8d2 100644 --- a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs @@ -1,5 +1,5 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.IO; diff --git a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs index ccccca98e..0d214f58d 100644 --- a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs @@ -5,8 +5,6 @@ using MediaBrowser.Model.Logging; using MediaBrowser.XbmcMetadata.Parsers; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs index e144142aa..368d37e0a 100644 --- a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs @@ -5,8 +5,6 @@ using MediaBrowser.Model.Logging; using MediaBrowser.XbmcMetadata.Parsers; using System.IO; using System.Threading; -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs index 9122d3046..ec53b3bc4 100644 --- a/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/AlbumNfoSaver.cs @@ -9,7 +9,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs index 38738470e..413738ade 100644 --- a/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/ArtistNfoSaver.cs @@ -9,7 +9,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index bf94afdeb..a5955e14d 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -18,7 +18,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs index e734b0640..bbd3a8d34 100644 --- a/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/EpisodeNfoSaver.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs index cdada7446..f32f89bc2 100644 --- a/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/MovieNfoSaver.cs @@ -10,7 +10,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs index 5c6b02360..85ed307c1 100644 --- a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs index e9a5d4d60..e9b2b786a 100644 --- a/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/SeriesNfoSaver.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Xml; -using MediaBrowser.Common.IO; + using MediaBrowser.Controller.IO; using MediaBrowser.Model.IO; using MediaBrowser.Model.Xml; diff --git a/SocketHttpListener/Net/HttpResponseStream.Managed.cs b/SocketHttpListener/Net/HttpResponseStream.Managed.cs index d6bb2c04a..2f580a104 100644 --- a/SocketHttpListener/Net/HttpResponseStream.Managed.cs +++ b/SocketHttpListener/Net/HttpResponseStream.Managed.cs @@ -174,14 +174,7 @@ namespace SocketHttpListener.Net } else { - try - { - _stream.Write(buffer, offset, count); - } - catch (Exception ex) - { - throw new HttpListenerException(ex.HResult, ex.Message); - } + _stream.Write(buffer, offset, count); } } @@ -266,25 +259,7 @@ namespace SocketHttpListener.Net InternalWrite(bytes, 0, bytes.Length); } - try - { - return _stream.BeginWrite(buffer, offset, size, cback, state); - } - catch (Exception ex) - { - if (_ignore_errors) - { - HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this); - ares._callback = cback; - ares._state = state; - ares.Complete(); - return ares; - } - else - { - throw new HttpListenerException(ex.HResult, ex.Message); - } - } + return _stream.BeginWrite(buffer, offset, size, cback, state); } private void EndWriteCore(IAsyncResult asyncResult) @@ -304,24 +279,9 @@ namespace SocketHttpListener.Net } else { - try - { - _stream.EndWrite(asyncResult); - if (_response.SendChunked) - _stream.Write(s_crlf, 0, 2); - } - catch (Exception ex) - { - // NetworkStream wraps exceptions in IOExceptions; if the underlying socket operation - // failed because of invalid arguments or usage, propagate that error. Otherwise - // wrap the whole thing in an HttpListenerException. This is all to match Windows behavior. - if (ex.InnerException is ArgumentException || ex.InnerException is InvalidOperationException || ex.InnerException is SocketException) - { - throw ex.InnerException; - } - - throw new HttpListenerException(ex.HResult, ex.Message); - } + _stream.EndWrite(asyncResult); + if (_response.SendChunked) + _stream.Write(s_crlf, 0, 2); } } @@ -359,7 +319,32 @@ namespace SocketHttpListener.Net } //_logger.Info("Socket sending file {0} {1}", path, response.ContentLength64); - return _socket.SendFile(path, preBuffer, _emptyBuffer, cancellationToken); + + var taskCompletion = new TaskCompletionSource(); + + Action callback = callbackResult => + { + try + { + _socket.EndSendFile(callbackResult); + taskCompletion.TrySetResult(true); + } + catch (Exception ex) + { + taskCompletion.TrySetException(ex); + } + }; + + var result = _socket.BeginSendFile(path, preBuffer, _emptyBuffer, new AsyncCallback(callback), null); + + if (result.CompletedSynchronously) + { + callback(result); + } + + cancellationToken.Register(() => taskCompletion.TrySetCanceled()); + + return taskCompletion.Task; } const int StreamCopyToBufferSize = 81920; -- cgit v1.2.3