aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/HttpServer/HttpResultFactory.cs')
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs268
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.