diff options
Diffstat (limited to 'Emby.Server.Implementations/HttpServer/HttpResultFactory.cs')
| -rw-r--r-- | Emby.Server.Implementations/HttpServer/HttpResultFactory.cs | 268 |
1 files changed, 66 insertions, 202 deletions
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 396bd8e88..f5a1fe246 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -6,19 +6,16 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; -using System.IO.Compression; using System.Net; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Xml; -using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.Services; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using IRequest = MediaBrowser.Model.Services.IRequest; using MimeTypes = MediaBrowser.Model.Net.MimeTypes; -using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter; namespace Emby.Server.Implementations.HttpServer { @@ -193,50 +190,37 @@ namespace Emby.Server.Implementations.HttpServer /// <returns></returns> public object ToOptimizedResult<T>(IRequest request, T dto) { - var compressionType = GetCompressionType(request); - if (compressionType == null) - { - var contentType = request.ResponseContentType; + var contentType = request.ResponseContentType; - switch (GetRealContentType(contentType)) - { - case "application/xml": - case "text/xml": - case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return SerializeToXmlString(dto); - - case "application/json": - case "text/json": - return _jsonSerializer.SerializeToString(dto); - } - } - - // Do not use the memoryStreamFactory here, they don't place nice with compression - using (var ms = new MemoryStream()) + switch (GetRealContentType(contentType)) { - var contentType = request.ResponseContentType; - var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); + case "application/xml": + case "text/xml": + case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml + return SerializeToXmlString(dto); - writerFn(dto, ms); + case "application/json": + case "text/json": + return _jsonSerializer.SerializeToString(dto); + default: + { + var ms = new MemoryStream(); + var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); - ms.Position = 0; + writerFn(dto, ms); + + ms.Position = 0; - var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase)) + { + return GetHttpResult(new byte[] { }, contentType, true); + } - return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result; + return GetHttpResult(ms, contentType, true); + } } } - 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 @@ -440,11 +424,14 @@ namespace Emby.Server.Implementations.HttpServer options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - // Quotes are valid in linux. They'll possibly cause issues here - var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty); - if (!string.IsNullOrWhiteSpace(filename)) + if (!options.ResponseHeaders.ContainsKey("Content-Disposition")) { - options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\""; + // Quotes are valid in linux. They'll possibly cause issues here + var filename = (Path.GetFileName(path) ?? string.Empty).Replace("\"", string.Empty); + if (!string.IsNullOrWhiteSpace(filename)) + { + options.ResponseHeaders["Content-Disposition"] = "inline; filename=\"" + filename + "\""; + } } return GetStaticResult(requestContext, options); @@ -503,190 +490,67 @@ namespace Emby.Server.Implementations.HttpServer return result; } - var compress = ShouldCompressResponse(requestContext, contentType); - var hasHeaders = await GetStaticResult(requestContext, options, compress).ConfigureAwait(false); - AddResponseHeaders(hasHeaders, options.ResponseHeaders); - - return hasHeaders; - } - - /// <summary> - /// Shoulds the compress response. - /// </summary> - /// <param name="requestContext">The request context.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool ShouldCompressResponse(IRequest requestContext, string contentType) - { - // It will take some work to support compression with byte range requests - if (!string.IsNullOrWhiteSpace(requestContext.Headers.Get("Range"))) - { - return false; - } - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Don't compress images - if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(contentType, "application/x-javascript", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - if (string.Equals(contentType, "application/xml", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - return false; - } - - return true; - } - - /// <summary> - /// The us culture - /// </summary> - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - private async Task<IHasHeaders> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress) - { var isHeadRequest = options.IsHeadRequest; var factoryFn = options.ContentFactory; - var contentType = options.ContentType; var responseHeaders = options.ResponseHeaders; - var requestedCompressionType = GetCompressionType(requestContext); - - if (!compress || string.IsNullOrEmpty(requestedCompressionType)) - { - var rangeHeader = requestContext.Headers.Get("Range"); - - if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path)) - { - return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem) - { - OnComplete = options.OnComplete, - OnError = options.OnError, - FileShare = options.FileShare - }; - } + //var requestedCompressionType = GetCompressionType(requestContext); - if (!string.IsNullOrWhiteSpace(rangeHeader)) - { - var stream = await factoryFn().ConfigureAwait(false); + var rangeHeader = requestContext.Headers.Get("Range"); - return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) - { - OnComplete = options.OnComplete - }; - } - else + if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path)) + { + var hasHeaders = new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem) { - var stream = await factoryFn().ConfigureAwait(false); - - responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture); - - if (isHeadRequest) - { - stream.Dispose(); - - return GetHttpResult(new byte[] { }, contentType, true); - } + OnComplete = options.OnComplete, + OnError = options.OnError, + FileShare = options.FileShare + }; - return new StreamWriter(stream, contentType, _logger) - { - OnComplete = options.OnComplete, - OnError = options.OnError - }; - } + AddResponseHeaders(hasHeaders, options.ResponseHeaders); + return hasHeaders; } - using (var stream = await factoryFn().ConfigureAwait(false)) + if (!string.IsNullOrWhiteSpace(rangeHeader)) { - return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false); - } - } + var stream = await factoryFn().ConfigureAwait(false); - private async Task<IHasHeaders> GetCompressedResult(Stream stream, - string requestedCompressionType, - IDictionary<string, string> responseHeaders, - bool isHeadRequest, - string contentType) - { - using (var reader = new MemoryStream()) - { - await stream.CopyToAsync(reader).ConfigureAwait(false); - - reader.Position = 0; - var content = reader.ToArray(); - - if (content.Length >= 1024) + var hasHeaders = new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest, _logger) { - content = Compress(content, requestedCompressionType); - responseHeaders["Content-Encoding"] = requestedCompressionType; - } + OnComplete = options.OnComplete + }; - responseHeaders["Vary"] = "Accept-Encoding"; - responseHeaders["Content-Length"] = content.Length.ToString(UsCulture); + AddResponseHeaders(hasHeaders, options.ResponseHeaders); + return hasHeaders; + } + else + { + var stream = await factoryFn().ConfigureAwait(false); + + responseHeaders["Content-Length"] = stream.Length.ToString(UsCulture); if (isHeadRequest) { + stream.Dispose(); + return GetHttpResult(new byte[] { }, contentType, true); } - return GetHttpResult(content, contentType, true, responseHeaders); - } - } - - private byte[] Compress(byte[] bytes, string compressionType) - { - if (compressionType == "deflate") - return Deflate(bytes); - - if (compressionType == "gzip") - return GZip(bytes); - - throw new NotSupportedException(compressionType); - } - - 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 - using (var ms = new MemoryStream()) - using (var zipStream = new DeflateStream(ms, CompressionMode.Compress)) - { - zipStream.Write(bytes, 0, bytes.Length); - zipStream.Dispose(); + var hasHeaders = new StreamWriter(stream, contentType, _logger) + { + OnComplete = options.OnComplete, + OnError = options.OnError + }; - return ms.ToArray(); + AddResponseHeaders(hasHeaders, options.ResponseHeaders); + return hasHeaders; } } - private byte[] GZip(byte[] buffer) - { - using (var ms = new MemoryStream()) - using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) - { - zipStream.Write(buffer, 0, buffer.Length); - zipStream.Dispose(); - - return ms.ToArray(); - } - } + /// <summary> + /// The us culture + /// </summary> + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// <summary> /// Adds the caching responseHeaders. |
