diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-11-10 09:41:24 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2016-11-10 09:41:24 -0500 |
| commit | 227dd0a42d398978ca085a607345a7877de87950 (patch) | |
| tree | 19f3d394d5be259fd32ea04e4f966082372e1715 /MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs | |
| parent | c1ae3ec2ce803b16fa9ecc0981865aa7c9be172b (diff) | |
rework result factory
Diffstat (limited to 'MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs | 158 |
1 files changed, 152 insertions, 6 deletions
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index 4c251ba24..b013a0952 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -6,13 +6,17 @@ 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 MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using ServiceStack; +using ServiceStack.Host; using IRequest = MediaBrowser.Model.Services.IRequest; using MimeTypes = MediaBrowser.Model.Net.MimeTypes; using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter; @@ -30,6 +34,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; + private readonly IXmlSerializer _xmlSerializer; /// <summary> /// Initializes a new instance of the <see cref="HttpResultFactory" /> class. @@ -37,10 +42,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer /// <param name="logManager">The log manager.</param> /// <param name="fileSystem">The file system.</param> /// <param name="jsonSerializer">The json serializer.</param> - public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer) + public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer) { _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; + _xmlSerializer = xmlSerializer; _logger = logManager.GetLogger("HttpResultFactory"); } @@ -130,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer throw new ArgumentNullException("result"); } - var optimizedResult = requestContext.ToOptimizedResult(result); + var optimizedResult = ToOptimizedResult(requestContext, result); if (responseHeaders == null) { @@ -152,7 +158,99 @@ namespace MediaBrowser.Server.Implementations.HttpServer return optimizedResult; } - + + public static string GetCompressionType(IRequest request) + { + var prefs = new RequestPreferences(request); + + if (prefs.AcceptsDeflate) + return "deflate"; + + if (prefs.AcceptsGzip) + return "gzip"; + + return null; + } + + /// <summary> + /// Returns the optimized result for the IRequestContext. + /// Does not use or store results in any cache. + /// </summary> + /// <param name="request"></param> + /// <param name="dto"></param> + /// <returns></returns> + public object ToOptimizedResult<T>(IRequest request, T dto) + { + request.Response.Dto = dto; + + var compressionType = GetCompressionType(request); + if (compressionType == null) + { + var contentType = request.ResponseContentType; + var contentTypeAttr = ContentFormat.GetEndpointAttributes(contentType); + + switch (contentTypeAttr) + { + case RequestAttributes.Xml: + return SerializeToXmlString(dto); + + case RequestAttributes.Json: + return _jsonSerializer.SerializeToString(dto); + } + } + + using (var ms = new MemoryStream()) + { + using (var compressionStream = GetCompressionStream(ms, compressionType)) + { + ContentTypes.Instance.SerializeToStream(request, dto, compressionStream); + compressionStream.Close(); + + var compressedBytes = ms.ToArray(); + + var httpResult = new HttpResult(compressedBytes, request.ResponseContentType) + { + Status = request.Response.StatusCode + }; + + httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture); + httpResult.Headers["Content-Encoding"] = compressionType; + + return httpResult; + } + } + } + + public static string SerializeToXmlString(object from) + { + using (var ms = new MemoryStream()) + { + var xwSettings = new XmlWriterSettings(); + xwSettings.Encoding = new UTF8Encoding(false); + xwSettings.OmitXmlDeclaration = false; + + using (var xw = XmlWriter.Create(ms, xwSettings)) + { + var serializer = new DataContractSerializer(from.GetType()); + serializer.WriteObject(xw, from); + xw.Flush(); + ms.Seek(0, SeekOrigin.Begin); + var reader = new StreamReader(ms); + return reader.ReadToEnd(); + } + } + } + + 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); + } + /// <summary> /// Gets the optimized result using cache. /// </summary> @@ -471,7 +569,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer var contentType = options.ContentType; var responseHeaders = options.ResponseHeaders; - var requestedCompressionType = requestContext.GetCompressionType(); + var requestedCompressionType = GetCompressionType(requestContext); if (!compress || string.IsNullOrEmpty(requestedCompressionType)) { @@ -513,16 +611,64 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } - var contents = content.Compress(requestedCompressionType); + var contents = Compress(content, requestedCompressionType); responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture); + responseHeaders["Content-Encoding"] = requestedCompressionType; if (isHeadRequest) { return GetHttpResult(new byte[] { }, contentType); } - return new CompressedResult(contents, requestedCompressionType, contentType); + return GetHttpResult(contents, contentType, responseHeaders); + } + + public static byte[] Compress(string text, string compressionType) + { + if (compressionType == "deflate") + return Deflate(text); + + if (compressionType == "gzip") + return GZip(text); + + throw new NotSupportedException(compressionType); + } + + public static byte[] Deflate(string text) + { + return Deflate(Encoding.UTF8.GetBytes(text)); + } + + public static 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.Close(); + + return ms.ToArray(); + } + } + + public static byte[] GZip(string text) + { + return GZip(Encoding.UTF8.GetBytes(text)); + } + + public static byte[] GZip(byte[] buffer) + { + using (var ms = new MemoryStream()) + using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) + { + zipStream.Write(buffer, 0, buffer.Length); + zipStream.Close(); + + return ms.ToArray(); + } } /// <summary> |
