diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer')
10 files changed, 97 insertions, 334 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 51a53fe21..9ec671908 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -19,6 +19,7 @@ using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Security; using MediaBrowser.Model.Extensions; @@ -45,16 +46,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer private readonly IServerConfigurationManager _config; private readonly INetworkManager _networkManager; + private readonly IMemoryStreamProvider _memoryStreamProvider; public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, IServerConfigurationManager config, string serviceName, - string defaultRedirectPath, INetworkManager networkManager, params Assembly[] assembliesWithServices) + string defaultRedirectPath, INetworkManager networkManager, IMemoryStreamProvider memoryStreamProvider, params Assembly[] assembliesWithServices) : base(serviceName, assembliesWithServices) { DefaultRedirectPath = defaultRedirectPath; _networkManager = networkManager; + _memoryStreamProvider = memoryStreamProvider; _config = config; _logger = logManager.GetLogger("HttpServer"); @@ -71,42 +74,47 @@ namespace MediaBrowser.Server.Implementations.HttpServer HostConfig.Instance.MapExceptionToStatusCode = new Dictionary<Type, int> { - {typeof (InvalidOperationException), 422}, + {typeof (InvalidOperationException), 500}, + {typeof (NotImplementedException), 500}, {typeof (ResourceNotFoundException), 404}, {typeof (FileNotFoundException), 404}, {typeof (DirectoryNotFoundException), 404}, {typeof (SecurityException), 401}, {typeof (PaymentRequiredException), 402}, {typeof (UnauthorizedAccessException), 500}, - {typeof (ApplicationException), 500} + {typeof (ApplicationException), 500}, + {typeof (PlatformNotSupportedException), 500}, + {typeof (NotSupportedException), 500} }; HostConfig.Instance.GlobalResponseHeaders = new Dictionary<string, string>(); HostConfig.Instance.DebugMode = false; HostConfig.Instance.LogFactory = LogManager.LogFactory; + HostConfig.Instance.AllowJsonpRequests = false; // The Markdown feature causes slow startup times (5 mins+) on cold boots for some users // Custom format allows images - HostConfig.Instance.EnableFeatures = Feature.Csv | Feature.Html | Feature.Json | Feature.Jsv | Feature.Metadata | Feature.Xml | Feature.CustomFormat; + HostConfig.Instance.EnableFeatures = Feature.Html | Feature.Json | Feature.Xml | Feature.CustomFormat; container.Adapter = _containerAdapter; - Plugins.Add(new SwaggerFeature()); + Plugins.RemoveAll(x => x is NativeTypesFeature); + //Plugins.Add(new SwaggerFeature()); Plugins.Add(new CorsFeature(allowedHeaders: "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization")); //Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { // new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()), //})); - PreRequestFilters.Add((httpReq, httpRes) => - { - //Handles Request and closes Responses after emitting global HTTP Headers - if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) - { - httpRes.EndRequest(); //add a 'using ServiceStack;' - } - }); + //PreRequestFilters.Add((httpReq, httpRes) => + //{ + // //Handles Request and closes Responses after emitting global HTTP Headers + // if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) + // { + // httpRes.EndRequest(); //add a 'using ServiceStack;' + // } + //}); HostContext.GlobalResponseFilters.Add(new ResponseFilter(_logger).FilterResponse); } @@ -176,7 +184,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private IHttpListener GetListener() { - return new WebSocketSharpListener(_logger, CertificatePath); + return new WebSocketSharpListener(_logger, CertificatePath, _memoryStreamProvider); } private void OnWebSocketConnecting(WebSocketConnectingEventArgs args) @@ -400,6 +408,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer return; } + if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase)) + { + httpRes.StatusCode = 200; + httpRes.AddHeader("Access-Control-Allow-Origin", "*"); + httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); + httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization"); + httpRes.ContentType = "text/html"; + + httpRes.Close(); + } + var operationName = httpReq.OperationName; var localPath = url.LocalPath; @@ -528,8 +547,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - - throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo); + else + { + httpRes.Close(); + } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index c55e98388..10d6f7493 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -93,12 +93,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - - if (responseHeaders != null) + if (responseHeaders == null) { - AddResponseHeaders(result, responseHeaders); + responseHeaders = new Dictionary<string, string>(); } + responseHeaders["Expires"] = "-1"; + AddResponseHeaders(result, responseHeaders); + return result; } @@ -681,29 +683,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } - /// <summary> - /// Gets the error result. - /// </summary> - /// <param name="statusCode">The status code.</param> - /// <param name="errorMessage">The error message.</param> - /// <param name="responseHeaders">The response headers.</param> - /// <returns>System.Object.</returns> - public void ThrowError(int statusCode, string errorMessage, IDictionary<string, string> responseHeaders = null) - { - var error = new HttpError - { - Status = statusCode, - ErrorCode = errorMessage - }; - - if (responseHeaders != null) - { - AddResponseHeaders(error, responseHeaders); - } - - throw error; - } - public object GetAsyncStreamWriter(IAsyncStreamSource streamSource) { return new AsyncStreamWriter(streamSource); diff --git a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs deleted file mode 100644 index cac2f8e09..000000000 --- a/MediaBrowser.Server.Implementations/HttpServer/NativeWebSocket.cs +++ /dev/null @@ -1,240 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using WebSocketMessageType = MediaBrowser.Model.Net.WebSocketMessageType; -using WebSocketState = MediaBrowser.Model.Net.WebSocketState; - -namespace MediaBrowser.Server.Implementations.HttpServer -{ - /// <summary> - /// Class NativeWebSocket - /// </summary> - public class NativeWebSocket : IWebSocket - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - public event EventHandler<EventArgs> Closed; - - /// <summary> - /// Gets or sets the web socket. - /// </summary> - /// <value>The web socket.</value> - private System.Net.WebSockets.WebSocket WebSocket { get; set; } - - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - /// <summary> - /// Initializes a new instance of the <see cref="NativeWebSocket" /> class. - /// </summary> - /// <param name="socket">The socket.</param> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">socket</exception> - public NativeWebSocket(WebSocket socket, ILogger logger) - { - if (socket == null) - { - throw new ArgumentNullException("socket"); - } - - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - _logger = logger; - WebSocket = socket; - - Receive(); - } - - /// <summary> - /// Gets or sets the state. - /// </summary> - /// <value>The state.</value> - public WebSocketState State - { - get - { - WebSocketState commonState; - - if (!Enum.TryParse(WebSocket.State.ToString(), true, out commonState)) - { - _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.State.ToString()); - } - - return commonState; - } - } - - /// <summary> - /// Receives this instance. - /// </summary> - private async void Receive() - { - while (true) - { - byte[] bytes; - - try - { - bytes = await ReceiveBytesAsync(_cancellationTokenSource.Token).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - break; - } - catch (WebSocketException ex) - { - _logger.ErrorException("Error receiving web socket message", ex); - - break; - } - - if (bytes == null) - { - // Connection closed - EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); - break; - } - - if (OnReceiveBytes != null) - { - OnReceiveBytes(bytes); - } - } - } - - /// <summary> - /// Receives the async. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{WebSocketMessageInfo}.</returns> - /// <exception cref="System.Net.WebSockets.WebSocketException">Connection closed</exception> - private async Task<byte[]> ReceiveBytesAsync(CancellationToken cancellationToken) - { - var bytes = new byte[4096]; - var buffer = new ArraySegment<byte>(bytes); - - var result = await WebSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); - - if (result.CloseStatus.HasValue) - { - _logger.Info("Web socket connection closed by client. Reason: {0}", result.CloseStatus.Value); - return null; - } - - return buffer.Array; - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="type">The type.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) - { - System.Net.WebSockets.WebSocketMessageType nativeType; - - if (!Enum.TryParse(type.ToString(), true, out nativeType)) - { - _logger.Warn("Unrecognized WebSocketMessageType: {0}", type.ToString()); - } - - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); - - return WebSocket.SendAsync(new ArraySegment<byte>(bytes), nativeType, true, linkedTokenSource.Token); - } - - public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) - { - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); - - return WebSocket.SendAsync(new ArraySegment<byte>(bytes), System.Net.WebSockets.WebSocketMessageType.Binary, true, linkedTokenSource.Token); - } - - public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) - { - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); - - var bytes = Encoding.UTF8.GetBytes(text); - - return WebSocket.SendAsync(new ArraySegment<byte>(bytes), System.Net.WebSockets.WebSocketMessageType.Text, true, linkedTokenSource.Token); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - _cancellationTokenSource.Cancel(); - - WebSocket.Dispose(); - } - } - - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> - public Action<byte[]> OnReceiveBytes { get; set; } - - /// <summary> - /// Gets or sets the on receive. - /// </summary> - /// <value>The on receive.</value> - public Action<string> OnReceive { get; set; } - - /// <summary> - /// The _supports native web socket - /// </summary> - private static bool? _supportsNativeWebSocket; - - /// <summary> - /// Gets a value indicating whether [supports web sockets]. - /// </summary> - /// <value><c>true</c> if [supports web sockets]; otherwise, <c>false</c>.</value> - public static bool IsSupported - { - get - { - if (!_supportsNativeWebSocket.HasValue) - { - try - { - new ClientWebSocket(); - - _supportsNativeWebSocket = true; - } - catch (PlatformNotSupportedException) - { - _supportsNativeWebSocket = false; - } - } - - return _supportsNativeWebSocket.Value; - } - } - } -} diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs index 488c630fe..4b94095f5 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -191,15 +191,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - catch (IOException) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error in range request writer", ex); - throw; - } finally { if (OnComplete != null) @@ -251,15 +242,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } } - catch (IOException ex) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error in range request writer", ex); - throw; - } finally { if (OnComplete != null) diff --git a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs index cc351f6b3..8a7c14eb6 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/ServerFactory.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; @@ -15,23 +16,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// <summary> /// Creates the server. /// </summary> - /// <param name="applicationHost">The application host.</param> - /// <param name="logManager">The log manager.</param> - /// <param name="config">The configuration.</param> - /// <param name="_networkmanager">The _networkmanager.</param> - /// <param name="serverName">Name of the server.</param> - /// <param name="defaultRedirectpath">The default redirectpath.</param> /// <returns>IHttpServer.</returns> public static IHttpServer CreateServer(IApplicationHost applicationHost, ILogManager logManager, IServerConfigurationManager config, INetworkManager _networkmanager, + IMemoryStreamProvider streamProvider, string serverName, string defaultRedirectpath) { LogManager.LogFactory = new ServerLogFactory(logManager); - return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager); + return new HttpListenerHost(applicationHost, logManager, config, serverName, defaultRedirectpath, _networkmanager, streamProvider); } } } diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs index bfa65ac6b..d20dd7ec0 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/RequestMono.cs @@ -39,11 +39,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp if (boundary == null) return; - using (var requestStream = GetSubStream(InputStream)) + using (var requestStream = GetSubStream(InputStream, _memoryStreamProvider)) { //DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request //Not ending with \r\n? - var ms = new MemoryStream(32 * 1024); + var ms = _memoryStreamProvider.CreateNew(32 * 1024); await requestStream.CopyToAsync(ms).ConfigureAwait(false); var input = ms; @@ -229,9 +229,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp async Task LoadWwwForm() { - using (Stream input = GetSubStream(InputStream)) + using (Stream input = GetSubStream(InputStream, _memoryStreamProvider)) { - using (var ms = new MemoryStream()) + using (var ms = _memoryStreamProvider.CreateNew()) { await input.CopyToAsync(ms).ConfigureAwait(false); ms.Position = 0; diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs index bcc081eb1..b090c97c6 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Common.IO; namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { @@ -18,11 +19,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp private readonly ILogger _logger; private readonly string _certificatePath; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public WebSocketSharpListener(ILogger logger, string certificatePath) + public WebSocketSharpListener(ILogger logger, string certificatePath, IMemoryStreamProvider memoryStreamProvider) { _logger = logger; _certificatePath = certificatePath; + _memoryStreamProvider = memoryStreamProvider; } public Action<Exception, IRequest> ErrorHandler { get; set; } @@ -148,7 +151,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { var operationName = httpContext.Request.GetOperationName(); - var req = new WebSocketSharpRequest(httpContext, operationName, RequestAttributes.None, _logger); + var req = new WebSocketSharpRequest(httpContext, operationName, RequestAttributes.None, _logger, _memoryStreamProvider); req.RequestAttributes = req.GetAttributes(); return req; diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs index dc2aec3e1..b5c8d0107 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using Funq; +using MediaBrowser.Common.IO; using MediaBrowser.Model.Logging; using ServiceStack; using ServiceStack.Host; @@ -16,11 +17,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp public Container Container { get; set; } private readonly HttpListenerRequest request; private readonly IHttpResponse response; + private readonly IMemoryStreamProvider _memoryStreamProvider; - public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger) + public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, RequestAttributes requestAttributes, ILogger logger, IMemoryStreamProvider memoryStreamProvider) { this.OperationName = operationName; this.RequestAttributes = requestAttributes; + _memoryStreamProvider = memoryStreamProvider; this.request = httpContext.Request; this.response = new WebSocketSharpResponse(logger, httpContext.Response, this); @@ -403,7 +406,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp set { bufferedStream = value - ? bufferedStream ?? new MemoryStream(request.InputStream.ReadFully()) + ? bufferedStream ?? _memoryStreamProvider.CreateNew(request.InputStream.ReadFully()) : null; } } @@ -447,7 +450,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp } } - static Stream GetSubStream(Stream stream) + static Stream GetSubStream(Stream stream, IMemoryStreamProvider streamProvider) { if (stream is MemoryStream) { diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index e08be8bd1..a58645ec5 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs @@ -81,20 +81,12 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp public void Write(string text) { - try - { - var bOutput = System.Text.Encoding.UTF8.GetBytes(text); - response.ContentLength64 = bOutput.Length; + var bOutput = System.Text.Encoding.UTF8.GetBytes(text); + response.ContentLength64 = bOutput.Length; - var outputStream = response.OutputStream; - outputStream.Write(bOutput, 0, bOutput.Length); - Close(); - } - catch (Exception ex) - { - _logger.ErrorException("Could not WriteTextToResponse: " + ex.Message, ex); - throw; - } + var outputStream = response.OutputStream; + outputStream.Write(bOutput, 0, bOutput.Length); + Close(); } public void Close() diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs index ae408f8d6..5f122fb96 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading.Tasks; +using MediaBrowser.Common.IO; using ServiceStack; namespace MediaBrowser.Server.Implementations.HttpServer @@ -17,7 +18,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private ILogger Logger { get; set; } private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - + /// <summary> /// Gets or sets the source stream. /// </summary> @@ -39,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public Action OnComplete { get; set; } public Action OnError { get; set; } + private readonly byte[] _bytes; /// <summary> /// Initializes a new instance of the <see cref="StreamWriter" /> class. @@ -73,6 +75,17 @@ namespace MediaBrowser.Server.Implementations.HttpServer public StreamWriter(byte[] source, string contentType, ILogger logger) : this(new MemoryStream(source), contentType, logger) { + if (string.IsNullOrEmpty(contentType)) + { + throw new ArgumentNullException("contentType"); + } + + _bytes = source; + Logger = logger; + + Options["Content-Type"] = contentType; + + Options["Content-Length"] = source.Length.ToString(UsCulture); } private const int BufferSize = 81920; @@ -85,9 +98,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer { try { - using (var src = SourceStream) + if (_bytes != null) { - src.CopyTo(responseStream, BufferSize); + responseStream.Write(_bytes, 0, _bytes.Length); + } + else + { + using (var src = SourceStream) + { + src.CopyTo(responseStream, BufferSize); + } } } catch (Exception ex) @@ -114,9 +134,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer { try { - using (var src = SourceStream) + if (_bytes != null) + { + await responseStream.WriteAsync(_bytes, 0, _bytes.Length); + } + else { - await src.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); + using (var src = SourceStream) + { + await src.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); + } } } catch (Exception ex) |
