diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index 9e0aee325b..0c0ef894e4 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -554,7 +554,7 @@ namespace Emby.Server.Core ZipClient = new ZipClient(FileSystemManager); RegisterSingleInstance(ZipClient); - RegisterSingleInstance(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer, XmlSerializer)); + RegisterSingleInstance(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer, MemoryStreamFactory)); RegisterSingleInstance(this); RegisterSingleInstance(ApplicationPaths); @@ -614,6 +614,9 @@ namespace Emby.Server.Core RegisterSingleInstance(() => new SearchEngine(LogManager, LibraryManager, UserManager)); + CertificatePath = GetCertificatePath(true); + Certificate = GetCertificate(CertificatePath); + HttpServer = HttpServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, MemoryStreamFactory, "Emby", "web/index.html", textEncoding, SocketFactory, CryptographyProvider, JsonSerializer, XmlSerializer, EnvironmentInfo, Certificate); HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); RegisterSingleInstance(HttpServer, false); @@ -995,9 +998,6 @@ namespace Emby.Server.Core /// private void StartServer() { - CertificatePath = GetCertificatePath(true); - Certificate = GetCertificate(CertificatePath); - try { ServerManager.Start(GetUrlPrefixes()); diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index 64f498b124..41b7a4622e 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Threading.Tasks; using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer.SocketSharp; @@ -86,9 +87,7 @@ namespace Emby.Server.Implementations.HttpServer public string GlobalResponse { get; set; } - public override void Configure() - { - var mapExceptionToStatusCode = new Dictionary + readonly Dictionary _mapExceptionToStatusCode = new Dictionary { {typeof (InvalidOperationException), 500}, {typeof (NotImplementedException), 500}, @@ -102,6 +101,8 @@ namespace Emby.Server.Implementations.HttpServer {typeof (NotSupportedException), 500} }; + public override void Configure() + { var requestFilters = _appHost.GetExports().ToList(); foreach (var filter in requestFilters) { @@ -240,12 +241,15 @@ namespace Emby.Server.Implementations.HttpServer return; } - httpRes.StatusCode = 500; + int statusCode; + if (!_mapExceptionToStatusCode.TryGetValue(ex.GetType(), out statusCode)) + { + statusCode = 500; + } + httpRes.StatusCode = statusCode; httpRes.ContentType = "text/html"; - httpRes.Write(ex.Message); - - httpRes.Close(); + Write(httpRes, ex.Message); } catch { @@ -399,7 +403,7 @@ namespace Emby.Server.Implementations.HttpServer { httpRes.StatusCode = 400; httpRes.ContentType = "text/plain"; - httpRes.Write("Invalid host"); + Write(httpRes, "Invalid host"); return; } @@ -453,7 +457,7 @@ namespace Emby.Server.Implementations.HttpServer if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase)) { - httpRes.Write( + Write(httpRes, "EmbyPlease update your Emby bookmark to " + newUrl + ""); return; @@ -470,7 +474,7 @@ namespace Emby.Server.Implementations.HttpServer if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase)) { - httpRes.Write( + Write(httpRes, "EmbyPlease update your Emby bookmark to " + newUrl + ""); return; @@ -508,7 +512,7 @@ namespace Emby.Server.Implementations.HttpServer { httpRes.StatusCode = 503; httpRes.ContentType = "text/html"; - httpRes.Write(GlobalResponse); + Write(httpRes, GlobalResponse); return; } @@ -518,6 +522,10 @@ namespace Emby.Server.Implementations.HttpServer { await handler.ProcessRequestAsync(httpReq, httpRes, operationName).ConfigureAwait(false); } + else + { + ErrorHandler(new FileNotFoundException(), httpReq); + } } catch (Exception ex) { @@ -538,6 +546,15 @@ namespace Emby.Server.Implementations.HttpServer } } + private void Write(IResponse response, string text) + { + var bOutput = Encoding.UTF8.GetBytes(text); + response.SetContentLength(bOutput.Length); + + var outputStream = response.OutputStream; + outputStream.Write(bOutput, 0, bOutput.Length); + } + public static void RedirectToUrl(IResponse httpRes, string url) { httpRes.StatusCode = 302; diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index bbd5566616..f65331ec78 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -34,19 +34,16 @@ namespace Emby.Server.Implementations.HttpServer private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; - private readonly IXmlSerializer _xmlSerializer; + private readonly IMemoryStreamFactory _memoryStreamFactory; /// /// Initializes a new instance of the class. /// - /// The log manager. - /// The file system. - /// The json serializer. - public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer) + public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IMemoryStreamFactory memoryStreamFactory) { _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; - _xmlSerializer = xmlSerializer; + _memoryStreamFactory = memoryStreamFactory; _logger = logManager.GetLogger("HttpResultFactory"); } @@ -59,17 +56,13 @@ namespace Emby.Server.Implementations.HttpServer /// System.Object. public object GetResult(object content, string contentType, IDictionary responseHeaders = null) { - return GetHttpResult(content, contentType, responseHeaders); + return GetHttpResult(content, contentType, true, responseHeaders); } /// /// Gets the HTTP result. /// - /// The content. - /// Type of the content. - /// The response headers. - /// IHasHeaders. - private IHasHeaders GetHttpResult(object content, string contentType, IDictionary responseHeaders = null) + private IHasHeaders GetHttpResult(object content, string contentType, bool addCachePrevention, IDictionary responseHeaders = null) { IHasHeaders result; @@ -98,7 +91,7 @@ namespace Emby.Server.Implementations.HttpServer } else { - result = new HttpResult(content, contentType); + result = new HttpResult(content, contentType, HttpStatusCode.OK); } } } @@ -107,7 +100,11 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders = new Dictionary(); } - responseHeaders["Expires"] = "-1"; + if (addCachePrevention) + { + responseHeaders["Expires"] = "-1"; + } + AddResponseHeaders(result, responseHeaders); return result; @@ -184,8 +181,6 @@ namespace Emby.Server.Implementations.HttpServer /// public object ToOptimizedResult(IRequest request, T dto) { - request.Response.Dto = dto; - var compressionType = GetCompressionType(request); if (compressionType == null) { @@ -204,6 +199,7 @@ namespace Emby.Server.Implementations.HttpServer } } + // Do not use the memoryStreamFactory here, they don't place nice with compression using (var ms = new MemoryStream()) { using (var compressionStream = GetCompressionStream(ms, compressionType)) @@ -213,12 +209,9 @@ namespace Emby.Server.Implementations.HttpServer var compressedBytes = ms.ToArray(); - var httpResult = new HttpResult(compressedBytes, request.ResponseContentType) - { - Status = request.Response.StatusCode - }; + var httpResult = new StreamWriter(compressedBytes, request.ResponseContentType, _logger); - httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture); + //httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture); httpResult.Headers["Content-Encoding"] = compressionType; return httpResult; @@ -226,6 +219,16 @@ namespace Emby.Server.Implementations.HttpServer } } + private static Stream GetCompressionStream(Stream outputStream, string compressionType) + { + if (compressionType == "deflate") + return new DeflateStream(outputStream, CompressionMode.Compress, true); + if (compressionType == "gzip") + return new GZipStream(outputStream, CompressionMode.Compress, true); + + throw new NotSupportedException(compressionType); + } + public static string GetRealContentType(string contentType) { return contentType == null @@ -233,7 +236,7 @@ namespace Emby.Server.Implementations.HttpServer : contentType.Split(';')[0].ToLower().Trim(); } - public static string SerializeToXmlString(object from) + private string SerializeToXmlString(object from) { using (var ms = new MemoryStream()) { @@ -253,16 +256,6 @@ namespace Emby.Server.Implementations.HttpServer } } - private static Stream GetCompressionStream(Stream outputStream, string compressionType) - { - if (compressionType == "deflate") - return new DeflateStream(outputStream, CompressionMode.Compress); - if (compressionType == "gzip") - return new GZipStream(outputStream, CompressionMode.Compress); - - throw new NotSupportedException(compressionType); - } - /// /// Gets the optimized result using cache. /// @@ -358,23 +351,7 @@ namespace Emby.Server.Implementations.HttpServer return hasHeaders; } - IHasHeaders httpResult; - - var stream = result as Stream; - - if (stream != null) - { - httpResult = new StreamWriter(stream, contentType, _logger); - } - else - { - // Otherwise wrap into an HttpResult - httpResult = new HttpResult(result, contentType ?? "text/html", HttpStatusCode.NotModified); - } - - AddResponseHeaders(httpResult, responseHeaders); - - return httpResult; + return GetHttpResult(result, contentType, false, responseHeaders); } /// @@ -603,7 +580,7 @@ namespace Emby.Server.Implementations.HttpServer { stream.Dispose(); - return GetHttpResult(new byte[] { }, contentType); + return GetHttpResult(new byte[] { }, contentType, true); } return new StreamWriter(stream, contentType, _logger) @@ -630,13 +607,13 @@ namespace Emby.Server.Implementations.HttpServer if (isHeadRequest) { - return GetHttpResult(new byte[] { }, contentType); + return GetHttpResult(new byte[] { }, contentType, true); } - return GetHttpResult(contents, contentType, responseHeaders); + return GetHttpResult(contents, contentType, true, responseHeaders); } - public static byte[] Compress(string text, string compressionType) + private byte[] Compress(string text, string compressionType) { if (compressionType == "deflate") return Deflate(text); @@ -647,12 +624,12 @@ namespace Emby.Server.Implementations.HttpServer throw new NotSupportedException(compressionType); } - public static byte[] Deflate(string text) + private byte[] Deflate(string text) { return Deflate(Encoding.UTF8.GetBytes(text)); } - public static byte[] Deflate(byte[] bytes) + private byte[] Deflate(byte[] bytes) { // In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream // Which means we must use MemoryStream since you have to use ToArray() on a closed Stream @@ -666,12 +643,12 @@ namespace Emby.Server.Implementations.HttpServer } } - public static byte[] GZip(string text) + private byte[] GZip(string text) { return GZip(Encoding.UTF8.GetBytes(text)); } - public static byte[] GZip(byte[] buffer) + private byte[] GZip(byte[] buffer) { using (var ms = new MemoryStream()) using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index de0b33fe30..a8b1150567 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs @@ -77,18 +77,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp get { return _response.OutputStream; } } - public object Dto { get; set; } - - public void Write(string text) - { - var bOutput = System.Text.Encoding.UTF8.GetBytes(text); - _response.ContentLength64 = bOutput.Length; - - var outputStream = _response.OutputStream; - outputStream.Write(bOutput, 0, bOutput.Length); - Close(); - } - public void Close() { if (!this.IsClosed) @@ -110,8 +98,10 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp { try { - response.OutputStream.Flush(); - response.OutputStream.Dispose(); + var outputStream = response.OutputStream; + + outputStream.Flush(); + outputStream.Dispose(); response.Close(); } catch (Exception ex) @@ -120,16 +110,6 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp } } - public void End() - { - Close(); - } - - public void Flush() - { - _response.OutputStream.Flush(); - } - public bool IsClosed { get; diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs index 15488abaa8..33378949c3 100644 --- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs +++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs @@ -25,6 +25,8 @@ namespace Emby.Server.Implementations.HttpServer /// The source stream. private Stream SourceStream { get; set; } + private byte[] SourceBytes { get; set; } + /// /// The _options /// @@ -40,7 +42,6 @@ namespace Emby.Server.Implementations.HttpServer public Action OnComplete { get; set; } public Action OnError { get; set; } - private readonly byte[] _bytes; /// /// Initializes a new instance of the class. @@ -73,14 +74,13 @@ namespace Emby.Server.Implementations.HttpServer /// Type of the content. /// The logger. public StreamWriter(byte[] source, string contentType, ILogger logger) - : this(new MemoryStream(source), contentType, logger) { if (string.IsNullOrEmpty(contentType)) { throw new ArgumentNullException("contentType"); } - _bytes = source; + SourceBytes = source; Logger = logger; Headers["Content-Type"] = contentType; @@ -92,9 +92,11 @@ namespace Emby.Server.Implementations.HttpServer { try { - if (_bytes != null) + var bytes = SourceBytes; + + if (bytes != null) { - await responseStream.WriteAsync(_bytes, 0, _bytes.Length); + await responseStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } else { diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 224cd056aa..5a8be5a495 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -17,6 +17,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Net; namespace Emby.Server.Implementations.Images { @@ -146,7 +147,9 @@ namespace Emby.Server.Implementations.Images return ItemUpdateType.None; } - await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, false, cancellationToken).ConfigureAwait(false); + var mimeType = MimeTypes.GetMimeType(outputPath); + + await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).ConfigureAwait(false); return ItemUpdateType.ImageUpdate; } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index b8b0cb73c1..63356a8451 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -941,21 +941,20 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV await _liveStreamsSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - var result = _liveStreams.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase)); - - if (result != null && result.EnableStreamSharing) + try { - var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.EnableStreamSharing); - result.SharedStreamIds.Add(openedMediaSource.Id); - _liveStreamsSemaphore.Release(); + var result = _liveStreams.FirstOrDefault(i => string.Equals(i.OriginalStreamId, streamId, StringComparison.OrdinalIgnoreCase)); - _logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); + if (result != null && result.EnableStreamSharing) + { + var openedMediaSource = CloneMediaSource(result.OpenedMediaSource, result.EnableStreamSharing); + result.SharedStreamIds.Add(openedMediaSource.Id); - return new Tuple(result, openedMediaSource, result.TunerHost); - } + _logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); + + return new Tuple(result, openedMediaSource, result.TunerHost); + } - try - { foreach (var hostInstance in _liveTvManager.TunerHosts) { try @@ -1271,6 +1270,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV try { + var recorder = await GetRecorder().ConfigureAwait(false); + var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false); var liveStreamInfo = await GetChannelStreamInternal(timer.ChannelId, allMediaSources[0].Id, CancellationToken.None) @@ -1282,8 +1283,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV // HDHR doesn't seem to release the tuner right away after first probing with ffmpeg //await Task.Delay(3000, cancellationToken).ConfigureAwait(false); - var recorder = await GetRecorder().ConfigureAwait(false); - recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath); recordPath = EnsureFileUnique(recordPath, timer.Id); diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 960fe07397..300b67ae2f 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -566,6 +566,23 @@ namespace Emby.Server.Implementations.Session } } + private BaseItem GetNowPlayingItem(SessionInfo session, string itemId) + { + var idGuid = new Guid(itemId); + + var item = session.FullNowPlayingItem; + if (item != null && item.Id == idGuid) + { + return item; + } + + item = _libraryManager.GetItemById(itemId); + + session.FullNowPlayingItem = item; + + return item; + } + /// /// Used to report that playback has started for an item /// @@ -583,7 +600,7 @@ namespace Emby.Server.Implementations.Session var libraryItem = string.IsNullOrWhiteSpace(info.ItemId) ? null - : _libraryManager.GetItemById(new Guid(info.ItemId)); + : GetNowPlayingItem(session, info.ItemId); await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false); @@ -669,7 +686,7 @@ namespace Emby.Server.Implementations.Session var libraryItem = string.IsNullOrWhiteSpace(info.ItemId) ? null - : _libraryManager.GetItemById(new Guid(info.ItemId)); + : GetNowPlayingItem(session, info.ItemId); await UpdateNowPlayingItem(session, info, libraryItem).ConfigureAwait(false); @@ -773,7 +790,7 @@ namespace Emby.Server.Implementations.Session var libraryItem = string.IsNullOrWhiteSpace(info.ItemId) ? null - : _libraryManager.GetItemById(new Guid(info.ItemId)); + : GetNowPlayingItem(session, info.ItemId); // Normalize if (string.IsNullOrWhiteSpace(info.MediaSourceId)) @@ -1782,18 +1799,18 @@ namespace Emby.Server.Implementations.Session throw new ArgumentNullException("itemId"); } - var item = _libraryManager.GetItemById(new Guid(itemId)); + //var item = _libraryManager.GetItemById(new Guid(itemId)); - var info = GetItemInfo(item, null, null); + //var info = GetItemInfo(item, null, null); - ReportNowViewingItem(sessionId, info); + //ReportNowViewingItem(sessionId, info); } public void ReportNowViewingItem(string sessionId, BaseItemInfo item) { - var session = GetSession(sessionId); + //var session = GetSession(sessionId); - session.NowViewingItem = item; + //session.NowViewingItem = item; } public void ReportTranscodingInfo(string deviceId, TranscodingInfo info) diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index df491ce855..c1a7347b5f 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -142,6 +142,7 @@ + diff --git a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs index c4a25a9269..6bb3b6b804 100644 --- a/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs +++ b/MediaBrowser.Api/Playback/StaticRemoteStreamWriter.cs @@ -1,6 +1,8 @@ using MediaBrowser.Common.Net; using System.Collections.Generic; using System.IO; +using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Model.Services; namespace MediaBrowser.Api.Playback @@ -8,7 +10,7 @@ namespace MediaBrowser.Api.Playback /// /// Class StaticRemoteStreamWriter /// - public class StaticRemoteStreamWriter : IStreamWriter, IHasHeaders + public class StaticRemoteStreamWriter : IAsyncStreamWriter, IHasHeaders { /// /// The _input stream @@ -34,15 +36,11 @@ namespace MediaBrowser.Api.Playback get { return _options; } } - /// - /// Writes to. - /// - /// The response stream. - public void WriteTo(Stream responseStream) + public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) { using (_response) { - _response.Content.CopyTo(responseStream, 819200); + await _response.Content.CopyToAsync(responseStream, 81920, cancellationToken).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Api/TestService.cs b/MediaBrowser.Api/TestService.cs new file mode 100644 index 0000000000..5340b816cf --- /dev/null +++ b/MediaBrowser.Api/TestService.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Model.Services; + +namespace MediaBrowser.Api +{ + [Route("/Test/String", "GET")] + public class GetString + { + } + + [Route("/Test/OptimizedString", "GET")] + public class GetOptimizedString + { + } + + [Route("/Test/Bytes", "GET")] + public class GetBytes + { + } + + [Route("/Test/OptimizedBytes", "GET")] + public class GetOptimizedBytes + { + } + + [Route("/Test/Stream", "GET")] + public class GetStream + { + } + + [Route("/Test/OptimizedStream", "GET")] + public class GetOptimizedStream + { + } + + [Route("/Test/BytesWithContentType", "GET")] + public class GetBytesWithContentType + { + } + + public class TestService : BaseApiService + { + public object Get(GetString request) + { + return "Welcome to Emby!"; + } + public object Get(GetOptimizedString request) + { + return ToOptimizedResult("Welcome to Emby!"); + } + public object Get(GetBytes request) + { + return Encoding.UTF8.GetBytes("Welcome to Emby!"); + } + public object Get(GetOptimizedBytes request) + { + return ToOptimizedResult(Encoding.UTF8.GetBytes("Welcome to Emby!")); + } + public object Get(GetBytesWithContentType request) + { + return ApiEntryPoint.Instance.ResultFactory.GetResult(Encoding.UTF8.GetBytes("Welcome to Emby!"), "text/html"); + } + public object Get(GetStream request) + { + return new MemoryStream(Encoding.UTF8.GetBytes("Welcome to Emby!")); + } + public object Get(GetOptimizedStream request) + { + return ToOptimizedResult(new MemoryStream(Encoding.UTF8.GetBytes("Welcome to Emby!"))); + } + } +} diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index b3e82f9258..343b15a04f 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Session; using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Session { @@ -106,7 +107,9 @@ namespace MediaBrowser.Controller.Session /// /// The now playing item. public BaseItemInfo NowPlayingItem { get; set; } - + + public BaseItem FullNowPlayingItem { get; set; } + /// /// Gets or sets the device id. /// diff --git a/MediaBrowser.Model/Services/IHttpResult.cs b/MediaBrowser.Model/Services/IHttpResult.cs index 36ffeb2847..fcb137c6b0 100644 --- a/MediaBrowser.Model/Services/IHttpResult.cs +++ b/MediaBrowser.Model/Services/IHttpResult.cs @@ -19,11 +19,6 @@ namespace MediaBrowser.Model.Services /// HttpStatusCode StatusCode { get; set; } - /// - /// The HTTP Status Description - /// - string StatusDescription { get; set; } - /// /// The HTTP Response ContentType /// diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index 5a4d240074..e9a9f1c5b5 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/MediaBrowser.Model/Services/IRequest.cs @@ -136,39 +136,12 @@ namespace MediaBrowser.Model.Services Stream OutputStream { get; } - /// - /// The Response DTO - /// - object Dto { get; set; } - - /// - /// Write once to the Response Stream then close it. - /// - /// - void Write(string text); - - /// - /// Buffer the Response OutputStream so it can be written in 1 batch - /// - bool UseBufferedStream { get; set; } - /// /// Signal that this response has been handled and no more processing should be done. /// When used in a request or response filter, no more filters or processing is done on this request. /// void Close(); - /// - /// Calls Response.End() on ASP.NET HttpResponse otherwise is an alias for Close(). - /// Useful when you want to prevent ASP.NET to provide it's own custom error page. - /// - void End(); - - /// - /// Response.Flush() and OutputStream.Flush() seem to have different behaviour in ASP.NET - /// - void Flush(); - /// /// Gets a value indicating whether this instance is closed. /// @@ -176,8 +149,6 @@ namespace MediaBrowser.Model.Services void SetContentLength(long contentLength); - bool KeepAlive { get; set; } - //Add Metadata to Response Dictionary Items { get; } } diff --git a/ServiceStack/Host/ContentTypes.cs b/ServiceStack/Host/ContentTypes.cs index 22fdc3e507..f7734a36b6 100644 --- a/ServiceStack/Host/ContentTypes.cs +++ b/ServiceStack/Host/ContentTypes.cs @@ -13,37 +13,23 @@ namespace ServiceStack.Host public void SerializeToStream(IRequest req, object response, Stream responseStream) { var contentType = req.ResponseContentType; - var serializer = GetResponseSerializer(contentType); - if (serializer == null) - throw new NotSupportedException("ContentType not supported: " + contentType); - - var httpRes = new HttpResponseStreamWrapper(responseStream, req) - { - Dto = req.Response.Dto - }; - serializer(req, response, httpRes); - } - - public Action GetResponseSerializer(string contentType) - { var serializer = GetStreamSerializer(contentType); - if (serializer == null) return null; - return (httpReq, dto, httpRes) => serializer(httpReq, dto, httpRes.OutputStream); + serializer(response, responseStream); } - public Action GetStreamSerializer(string contentType) + public static Action GetStreamSerializer(string contentType) { switch (GetRealContentType(contentType)) { case "application/xml": case "text/xml": case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return (r, o, s) => ServiceStackHost.Instance.SerializeToXml(o, s); + return (o, s) => ServiceStackHost.Instance.SerializeToXml(o, s); case "application/json": case "text/json": - return (r, o, s) => ServiceStackHost.Instance.SerializeToJson(o, s); + return (o, s) => ServiceStackHost.Instance.SerializeToJson(o, s); } return null; diff --git a/ServiceStack/Host/HttpResponseStreamWrapper.cs b/ServiceStack/Host/HttpResponseStreamWrapper.cs deleted file mode 100644 index 33038da722..0000000000 --- a/ServiceStack/Host/HttpResponseStreamWrapper.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Text; -using MediaBrowser.Model.Services; - -namespace ServiceStack.Host -{ - public class HttpResponseStreamWrapper : IHttpResponse - { - private static readonly UTF8Encoding UTF8EncodingWithoutBom = new UTF8Encoding(false); - - public HttpResponseStreamWrapper(Stream stream, IRequest request) - { - this.OutputStream = stream; - this.Request = request; - this.Headers = new Dictionary(); - this.Items = new Dictionary(); - } - - public Dictionary Headers { get; set; } - - public object OriginalResponse - { - get { return null; } - } - - public IRequest Request { get; private set; } - - public int StatusCode { set; get; } - public string StatusDescription { set; get; } - public string ContentType { get; set; } - - public void AddHeader(string name, string value) - { - this.Headers[name] = value; - } - - public string GetHeader(string name) - { - return this.Headers[name]; - } - - public void Redirect(string url) - { - this.Headers["Location"] = url; - } - - public Stream OutputStream { get; private set; } - - public object Dto { get; set; } - - public void Write(string text) - { - var bytes = UTF8EncodingWithoutBom.GetBytes(text); - OutputStream.Write(bytes, 0, bytes.Length); - } - - public bool UseBufferedStream { get; set; } - - public void Close() - { - if (IsClosed) return; - - OutputStream.Dispose(); - IsClosed = true; - } - - public void End() - { - Close(); - } - - public void Flush() - { - OutputStream.Flush(); - } - - public bool IsClosed { get; private set; } - - public void SetContentLength(long contentLength) {} - - public bool KeepAlive { get; set; } - - public Dictionary Items { get; private set; } - - public void SetCookie(Cookie cookie) - { - } - - public void ClearCookies() - { - } - } -} \ No newline at end of file diff --git a/ServiceStack/Host/ServiceController.cs b/ServiceStack/Host/ServiceController.cs index 703f06365a..7eb1253b32 100644 --- a/ServiceStack/Host/ServiceController.cs +++ b/ServiceStack/Host/ServiceController.cs @@ -210,9 +210,6 @@ namespace ServiceStack.Host //Executes the service and returns the result var response = await ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetOperationName()).ConfigureAwait(false); - if (req.Response.Dto == null) - req.Response.Dto = response; - return response; } } diff --git a/ServiceStack/HttpResponseExtensionsInternal.cs b/ServiceStack/HttpResponseExtensionsInternal.cs index 1195f63ca2..318d624294 100644 --- a/ServiceStack/HttpResponseExtensionsInternal.cs +++ b/ServiceStack/HttpResponseExtensionsInternal.cs @@ -6,6 +6,7 @@ using System.IO; using System.Net; using System.Threading.Tasks; using System.Collections.Generic; +using System.Text; using System.Threading; using MediaBrowser.Model.Services; using ServiceStack.Host; @@ -33,8 +34,11 @@ namespace ServiceStack var stream = result as Stream; if (stream != null) { - WriteTo(stream, response.OutputStream); - return true; + using (stream) + { + await stream.CopyToAsync(response.OutputStream).ConfigureAwait(false); + return true; + } } var bytes = result as byte[]; @@ -43,35 +47,13 @@ namespace ServiceStack response.ContentType = "application/octet-stream"; response.SetContentLength(bytes.Length); - response.OutputStream.Write(bytes, 0, bytes.Length); + await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); return true; } return false; } - public static long WriteTo(Stream inStream, Stream outStream) - { - var memoryStream = inStream as MemoryStream; - if (memoryStream != null) - { - memoryStream.WriteTo(outStream); - return memoryStream.Position; - } - - var data = new byte[4096]; - long total = 0; - int bytesRead; - - while ((bytesRead = inStream.Read(data, 0, data.Length)) > 0) - { - outStream.Write(data, 0, bytesRead); - total += bytesRead; - } - - return total; - } - /// /// End a ServiceStack Request with no content /// @@ -85,7 +67,7 @@ namespace ServiceStack httpRes.SetContentLength(0); } - public static Task WriteToResponse(this IResponse httpRes, MediaBrowser.Model.Services.IRequest httpReq, object result) + public static Task WriteToResponse(this IResponse httpRes, IRequest httpReq, object result) { if (result == null) { @@ -98,19 +80,10 @@ namespace ServiceStack { httpResult.RequestContext = httpReq; httpReq.ResponseContentType = httpResult.ContentType ?? httpReq.ResponseContentType; - var httpResSerializer = ContentTypes.Instance.GetResponseSerializer(httpReq.ResponseContentType); - return httpRes.WriteToResponse(httpResult, httpResSerializer, httpReq); + return httpRes.WriteToResponseInternal(httpResult, httpReq); } - var serializer = ContentTypes.Instance.GetResponseSerializer(httpReq.ResponseContentType); - return httpRes.WriteToResponse(result, serializer, httpReq); - } - - private static object GetDto(object response) - { - if (response == null) return null; - var httpResult = response as IHttpResult; - return httpResult != null ? httpResult.Response : response; + return httpRes.WriteToResponseInternal(result, httpReq); } /// @@ -119,17 +92,11 @@ namespace ServiceStack /// /// The response. /// Whether or not it was implicity handled by ServiceStack's built-in handlers. - /// The default action. /// The serialization context. /// - public static async Task WriteToResponse(this IResponse response, object result, Action defaultAction, MediaBrowser.Model.Services.IRequest request) + private static async Task WriteToResponseInternal(this IResponse response, object result, IRequest request) { var defaultContentType = request.ResponseContentType; - if (result == null) - { - response.EndRequestWithNoContent(); - return; - } var httpResult = result as IHttpResult; if (httpResult != null) @@ -137,10 +104,8 @@ namespace ServiceStack if (httpResult.RequestContext == null) httpResult.RequestContext = request; - response.Dto = response.Dto ?? GetDto(httpResult); - response.StatusCode = httpResult.Status; - response.StatusDescription = httpResult.StatusDescription ?? httpResult.StatusCode.ToString(); + response.StatusDescription = httpResult.StatusCode.ToString(); if (string.IsNullOrEmpty(httpResult.ContentType)) { httpResult.ContentType = defaultContentType; @@ -159,21 +124,12 @@ namespace ServiceStack } } } - else - { - response.Dto = result; - } - /* Mono Error: Exception: Method not found: 'System.Web.HttpResponse.get_Headers' */ var responseOptions = result as IHasHeaders; if (responseOptions != null) { - //Reserving options with keys in the format 'xx.xxx' (No Http headers contain a '.' so its a safe restriction) - const string reservedOptions = "."; - foreach (var responseHeaders in responseOptions.Headers) { - if (responseHeaders.Key.Contains(reservedOptions)) continue; if (responseHeaders.Key == "Content-Length") { response.SetContentLength(long.Parse(responseHeaders.Value)); @@ -196,42 +152,41 @@ namespace ServiceStack response.ContentType += "; charset=utf-8"; } - var disposableResult = result as IDisposable; var writeToOutputStreamResult = await WriteToOutputStream(response, result).ConfigureAwait(false); if (writeToOutputStreamResult) { - response.Flush(); //required for Compression - if (disposableResult != null) disposableResult.Dispose(); return; } - if (httpResult != null) - result = httpResult.Response; - var responseText = result as string; if (responseText != null) { if (response.ContentType == null || response.ContentType == "text/html") response.ContentType = defaultContentType; - response.Write(responseText); + var bytes = Encoding.UTF8.GetBytes(responseText); + await response.OutputStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); return; } - if (defaultAction == null) - { - throw new ArgumentNullException("defaultAction", String.Format( - "As result '{0}' is not a supported responseType, a defaultAction must be supplied", - (result != null ? result.GetType().GetOperationName() : ""))); - } + await WriteObject(request, result, response).ConfigureAwait(false); + } + public static async Task WriteObject(IRequest request, object result, IResponse response) + { + var contentType = request.ResponseContentType; + var serializer = ContentTypes.GetStreamSerializer(contentType); + + using (var ms = new MemoryStream()) + { + serializer(result, ms); - if (result != null) - defaultAction(request, result, response); + ms.Position = 0; + response.SetContentLength(ms.Length); + await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false); + } - if (disposableResult != null) - disposableResult.Dispose(); + //serializer(result, outputStream); } - } } diff --git a/ServiceStack/HttpResult.cs b/ServiceStack/HttpResult.cs index 23a5cdffbb..3f86ffdf78 100644 --- a/ServiceStack/HttpResult.cs +++ b/ServiceStack/HttpResult.cs @@ -13,31 +13,7 @@ namespace ServiceStack public class HttpResult : IHttpResult, IAsyncStreamWriter { - public HttpResult() - : this((object)null, null) - { - } - - public HttpResult(object response) - : this(response, null) - { - } - - public HttpResult(object response, string contentType) - : this(response, contentType, HttpStatusCode.OK) - { - } - - public HttpResult(HttpStatusCode statusCode, string statusDescription) - : this() - { - StatusCode = statusCode; - StatusDescription = statusDescription; - } - - public HttpResult(object response, HttpStatusCode statusCode) - : this(response, null, statusCode) - { } + public object Response { get; set; } public HttpResult(object response, string contentType, HttpStatusCode statusCode) { @@ -49,102 +25,12 @@ namespace ServiceStack this.StatusCode = statusCode; } - public HttpResult(Stream responseStream, string contentType) - : this(null, contentType, HttpStatusCode.OK) - { - this.ResponseStream = responseStream; - } - - public HttpResult(string responseText, string contentType) - : this(null, contentType, HttpStatusCode.OK) - { - this.ResponseText = responseText; - } - - public HttpResult(byte[] responseBytes, string contentType) - : this(null, contentType, HttpStatusCode.OK) - { - this.ResponseStream = new MemoryStream(responseBytes); - } - - public string ResponseText { get; private set; } - - public Stream ResponseStream { get; private set; } - public string ContentType { get; set; } public IDictionary Headers { get; private set; } public List Cookies { get; private set; } - public string ETag { get; set; } - - public TimeSpan? Age { get; set; } - - public TimeSpan? MaxAge { get; set; } - - public DateTime? Expires { get; set; } - - public DateTime? LastModified { get; set; } - - public Func ResultScope { get; set; } - - public string Location - { - set - { - if (StatusCode == HttpStatusCode.OK) - StatusCode = HttpStatusCode.Redirect; - - this.Headers["Location"] = value; - } - } - - public void SetPermanentCookie(string name, string value) - { - SetCookie(name, value, DateTime.UtcNow.AddYears(20), null); - } - - public void SetPermanentCookie(string name, string value, string path) - { - SetCookie(name, value, DateTime.UtcNow.AddYears(20), path); - } - - public void SetSessionCookie(string name, string value) - { - SetSessionCookie(name, value, null); - } - - public void SetSessionCookie(string name, string value, string path) - { - path = path ?? "/"; - this.Headers["Set-Cookie"] = string.Format("{0}={1};path=" + path, name, value); - } - - public void SetCookie(string name, string value, TimeSpan expiresIn, string path) - { - var expiresAt = DateTime.UtcNow.Add(expiresIn); - SetCookie(name, value, expiresAt, path); - } - - public void SetCookie(string name, string value, DateTime expiresAt, string path, bool secure = false, bool httpOnly = false) - { - path = path ?? "/"; - var cookie = string.Format("{0}={1};expires={2};path={3}", name, value, expiresAt.ToString("R"), path); - if (secure) - cookie += ";Secure"; - if (httpOnly) - cookie += ";HttpOnly"; - - this.Headers["Set-Cookie"] = cookie; - } - - public void DeleteCookie(string name) - { - var cookie = string.Format("{0}=;expires={1};path=/", name, DateTime.UtcNow.AddDays(-1).ToString("R")); - this.Headers["Set-Cookie"] = cookie; - } - public int Status { get; set; } public HttpStatusCode StatusCode @@ -153,75 +39,12 @@ namespace ServiceStack set { Status = (int)value; } } - public string StatusDescription { get; set; } - - public object Response { get; set; } - - public MediaBrowser.Model.Services.IRequest RequestContext { get; set; } - - public string View { get; set; } - - public string Template { get; set; } - - public int PaddingLength { get; set; } + public IRequest RequestContext { get; set; } public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) - { - try - { - await WriteToInternalAsync(responseStream, cancellationToken).ConfigureAwait(false); - responseStream.Flush(); - } - finally - { - DisposeStream(); - } - } - - public static Task WriteTo(Stream inStream, Stream outStream, CancellationToken cancellationToken) - { - var memoryStream = inStream as MemoryStream; - if (memoryStream != null) - { - memoryStream.WriteTo(outStream); - return Task.FromResult(true); - } - - return inStream.CopyToAsync(outStream, 81920, cancellationToken); - } - - public async Task WriteToInternalAsync(Stream responseStream, CancellationToken cancellationToken) { var response = RequestContext != null ? RequestContext.Response : null; - if (this.ResponseStream != null) - { - if (response != null) - { - var ms = ResponseStream as MemoryStream; - if (ms != null) - { - response.SetContentLength(ms.Length); - - await ms.CopyToAsync(responseStream, 81920, cancellationToken).ConfigureAwait(false); - return; - } - } - - await WriteTo(this.ResponseStream, responseStream, cancellationToken).ConfigureAwait(false); - return; - } - - if (this.ResponseText != null) - { - var bytes = Encoding.UTF8.GetBytes(this.ResponseText); - if (response != null) - response.SetContentLength(bytes.Length); - - await responseStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - return; - } - var bytesResponse = this.Response as byte[]; if (bytesResponse != null) { @@ -232,19 +55,7 @@ namespace ServiceStack return; } - ContentTypes.Instance.SerializeToStream(this.RequestContext, this.Response, responseStream); - } - - private void DisposeStream() - { - try - { - if (ResponseStream != null) - { - this.ResponseStream.Dispose(); - } - } - catch { /*ignore*/ } + await HttpResponseExtensionsInternal.WriteObject(this.RequestContext, this.Response, response).ConfigureAwait(false); } } } diff --git a/ServiceStack/ServiceStack.csproj b/ServiceStack/ServiceStack.csproj index 3402339a6c..5413d4e550 100644 --- a/ServiceStack/ServiceStack.csproj +++ b/ServiceStack/ServiceStack.csproj @@ -73,7 +73,6 @@ - diff --git a/SocketHttpListener.Portable/Ext.cs b/SocketHttpListener.Portable/Ext.cs index 303263d0b9..87f0887ed4 100644 --- a/SocketHttpListener.Portable/Ext.cs +++ b/SocketHttpListener.Portable/Ext.cs @@ -168,12 +168,6 @@ namespace SocketHttpListener : null; } - internal static void Close(this HttpListenerResponse response, HttpStatusCode code) - { - response.StatusCode = (int)code; - response.OutputStream.Dispose(); - } - internal static Stream Compress(this Stream stream, CompressionMethod method) { return method == CompressionMethod.Deflate diff --git a/SocketHttpListener.Portable/Net/EndPointListener.cs b/SocketHttpListener.Portable/Net/EndPointListener.cs index b50660ad0a..52385e2ba7 100644 --- a/SocketHttpListener.Portable/Net/EndPointListener.cs +++ b/SocketHttpListener.Portable/Net/EndPointListener.cs @@ -119,7 +119,6 @@ namespace SocketHttpListener.Net if (listener == null) return false; - context.Listener = listener; context.Connection.Prefix = prefix; return true; } @@ -129,7 +128,7 @@ namespace SocketHttpListener.Net if (context == null || context.Request == null) return; - context.Listener.UnregisterContext(context); + listener.UnregisterContext(context); } HttpListener SearchListener(Uri uri, out ListenerPrefix prefix) diff --git a/SocketHttpListener.Portable/Net/HttpConnection.cs b/SocketHttpListener.Portable/Net/HttpConnection.cs index d31da41329..db34c42185 100644 --- a/SocketHttpListener.Portable/Net/HttpConnection.cs +++ b/SocketHttpListener.Portable/Net/HttpConnection.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Text; -using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.IO; @@ -210,12 +209,7 @@ namespace SocketHttpListener.Net // TODO: can we get this stream before reading the input? if (o_stream == null) { - HttpListener listener = context.Listener; - - if (listener == null) - return new ResponseStream(stream, context.Response, true, _memoryStreamFactory, _textEncoding); - - o_stream = new ResponseStream(stream, context.Response, listener.IgnoreWriteExceptions, _memoryStreamFactory, _textEncoding); + o_stream = new ResponseStream(stream, context.Response, _memoryStreamFactory, _textEncoding); } return o_stream; } @@ -257,7 +251,7 @@ namespace SocketHttpListener.Net Close(true); return; } - HttpListener listener = context.Listener; + HttpListener listener = epl.Listener; if (last_listener != listener) { RemoveConnection(); diff --git a/SocketHttpListener.Portable/Net/HttpListener.cs b/SocketHttpListener.Portable/Net/HttpListener.cs index 83660100ae..2b0f75d01f 100644 --- a/SocketHttpListener.Portable/Net/HttpListener.cs +++ b/SocketHttpListener.Portable/Net/HttpListener.cs @@ -28,7 +28,6 @@ namespace SocketHttpListener.Net HttpListenerPrefixCollection prefixes; AuthenticationSchemeSelector auth_selector; string realm; - bool ignore_write_exceptions; bool unsafe_ntlm_auth; bool listening; bool disposed; @@ -92,16 +91,6 @@ namespace SocketHttpListener.Net } } - public bool IgnoreWriteExceptions - { - get { return ignore_write_exceptions; } - set - { - CheckDisposed(); - ignore_write_exceptions = value; - } - } - public bool IsListening { get { return listening; } diff --git a/SocketHttpListener.Portable/Net/HttpListenerContext.cs b/SocketHttpListener.Portable/Net/HttpListenerContext.cs index 84c6a8c193..182fd2d2a4 100644 --- a/SocketHttpListener.Portable/Net/HttpListenerContext.cs +++ b/SocketHttpListener.Portable/Net/HttpListenerContext.cs @@ -18,7 +18,6 @@ namespace SocketHttpListener.Net HttpConnection cnc; string error; int err_status = 400; - internal HttpListener Listener; private readonly ILogger _logger; private readonly ICryptoProvider _cryptoProvider; private readonly IMemoryStreamFactory _memoryStreamFactory; diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs index 6ecbf97427..07788ea418 100644 --- a/SocketHttpListener.Portable/Net/ResponseStream.cs +++ b/SocketHttpListener.Portable/Net/ResponseStream.cs @@ -17,17 +17,15 @@ namespace SocketHttpListener.Net class ResponseStream : Stream { HttpListenerResponse response; - bool ignore_errors; bool disposed; bool trailer_sent; Stream stream; private readonly IMemoryStreamFactory _memoryStreamFactory; private readonly ITextEncoding _textEncoding; - internal ResponseStream(Stream stream, HttpListenerResponse response, bool ignore_errors, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding) + internal ResponseStream(Stream stream, HttpListenerResponse response, IMemoryStreamFactory memoryStreamFactory, ITextEncoding textEncoding) { this.response = response; - this.ignore_errors = ignore_errors; _memoryStreamFactory = memoryStreamFactory; _textEncoding = textEncoding; this.stream = stream; @@ -130,18 +128,7 @@ namespace SocketHttpListener.Net internal void InternalWrite(byte[] buffer, int offset, int count) { - if (ignore_errors) - { - try - { - stream.Write(buffer, offset, count); - } - catch { } - } - else - { - stream.Write(buffer, offset, count); - } + stream.Write(buffer, offset, count); } public override void Write(byte[] buffer, int offset, int count) @@ -214,23 +201,13 @@ namespace SocketHttpListener.Net InternalWrite(bytes, 0, bytes.Length); } - try - { - if (count > 0) - { - await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - - if (response.SendChunked) - stream.Write(crlf, 0, 2); - } - catch + if (count > 0) { - if (!ignore_errors) - { - throw; - } + await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); } + + if (response.SendChunked) + stream.Write(crlf, 0, 2); } //public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, diff --git a/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs b/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs index 426e15ecde..034ac17d20 100644 --- a/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/SocketHttpListener.Portable/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -322,7 +322,8 @@ namespace SocketHttpListener.Net.WebSockets internal void Close(HttpStatusCode code) { - _context.Response.Close(code); + _context.Response.StatusCode = (int)code; + _context.Response.OutputStream.Dispose(); } #endregion diff --git a/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj b/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj index f7b3a643cc..ee902462b0 100644 --- a/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj +++ b/SocketHttpListener.Portable/SocketHttpListener.Portable.csproj @@ -95,9 +95,8 @@ - if $(ConfigurationName) == Release ( -xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i -) + +