diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 7445fd3c28..e7e3308dc7 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.HttpServer /// private IHasHeaders GetHttpResult(IRequest requestContext, Stream content, string contentType, bool addCachePrevention, IDictionary responseHeaders = null) { - var result = new StreamWriter(content, contentType, _logger); + var result = new StreamWriter(content, contentType); if (responseHeaders == null) { @@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.HttpServer content = Array.Empty(); } - result = new StreamWriter(content, contentType, contentLength, _logger); + result = new StreamWriter(content, contentType, contentLength); } else { @@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders = new Dictionary(); } - if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires)) + if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _)) { responseHeaders["Expires"] = "-1"; } @@ -175,7 +175,7 @@ namespace Emby.Server.Implementations.HttpServer bytes = Array.Empty(); } - result = new StreamWriter(bytes, contentType, contentLength, _logger); + result = new StreamWriter(bytes, contentType, contentLength); } else { @@ -187,7 +187,7 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders = new Dictionary(); } - if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires)) + if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _)) { responseHeaders["Expires"] = "-1"; } @@ -277,9 +277,9 @@ namespace Emby.Server.Implementations.HttpServer private object ToOptimizedResultInternal(IRequest request, T dto, IDictionary responseHeaders = null) { - var contentType = request.ResponseContentType; + var contentType = request.ResponseContentType?.Split(';')[0]; - switch (GetRealContentType(contentType)) + switch (contentType) { case "application/xml": case "text/xml": @@ -333,13 +333,13 @@ namespace Emby.Server.Implementations.HttpServer if (isHeadRequest) { - var result = new StreamWriter(Array.Empty(), contentType, contentLength, _logger); + var result = new StreamWriter(Array.Empty(), contentType, contentLength); AddResponseHeaders(result, responseHeaders); return result; } else { - var result = new StreamWriter(content, contentType, contentLength, _logger); + var result = new StreamWriter(content, contentType, contentLength); AddResponseHeaders(result, responseHeaders); return result; } @@ -348,13 +348,19 @@ namespace Emby.Server.Implementations.HttpServer private byte[] Compress(byte[] bytes, string compressionType) { if (string.Equals(compressionType, "br", StringComparison.OrdinalIgnoreCase)) + { return CompressBrotli(bytes); + } if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase)) + { return Deflate(bytes); + } if (string.Equals(compressionType, "gzip", StringComparison.OrdinalIgnoreCase)) + { return GZip(bytes); + } throw new NotSupportedException(compressionType); } @@ -390,13 +396,6 @@ namespace Emby.Server.Implementations.HttpServer } } - public static string GetRealContentType(string contentType) - { - return contentType == null - ? null - : contentType.Split(';')[0].ToLowerInvariant().Trim(); - } - private static string SerializeToXmlString(object from) { using (var ms = new MemoryStream()) @@ -621,7 +620,7 @@ namespace Emby.Server.Implementations.HttpServer } } - var hasHeaders = new StreamWriter(stream, contentType, _logger) + var hasHeaders = new StreamWriter(stream, contentType) { OnComplete = options.OnComplete, OnError = options.OnError diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs index 3269d44cf6..cb2e3580b2 100644 --- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs +++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs @@ -14,8 +14,6 @@ namespace Emby.Server.Implementations.HttpServer /// public class StreamWriter : IAsyncStreamWriter, IHasHeaders { - private ILogger Logger { get; set; } - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// @@ -45,7 +43,7 @@ namespace Emby.Server.Implementations.HttpServer /// The source. /// Type of the content. /// The logger. - public StreamWriter(Stream source, string contentType, ILogger logger) + public StreamWriter(Stream source, string contentType) { if (string.IsNullOrEmpty(contentType)) { @@ -53,7 +51,6 @@ namespace Emby.Server.Implementations.HttpServer } SourceStream = source; - Logger = logger; Headers["Content-Type"] = contentType; @@ -69,7 +66,7 @@ namespace Emby.Server.Implementations.HttpServer /// The source. /// Type of the content. /// The logger. - public StreamWriter(byte[] source, string contentType, int contentLength, ILogger logger) + public StreamWriter(byte[] source, string contentType, int contentLength) { if (string.IsNullOrEmpty(contentType)) { @@ -77,7 +74,6 @@ namespace Emby.Server.Implementations.HttpServer } SourceBytes = source; - Logger = logger; Headers["Content-Type"] = contentType; diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index a363028760..f7ef16fb09 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -184,7 +184,7 @@ namespace Emby.Server.Implementations.LiveTv public QueryResult GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken) { - var user = query.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(query.UserId); + var user = query.UserId == Guid.Empty ? null : _userManager.GetUserById(query.UserId); var topFolder = GetInternalLiveTvFolder(cancellationToken); diff --git a/Emby.Server.Implementations/Serialization/JsonSerializer.cs b/Emby.Server.Implementations/Serialization/JsonSerializer.cs index 44898d4986..8ae7fd90cc 100644 --- a/Emby.Server.Implementations/Serialization/JsonSerializer.cs +++ b/Emby.Server.Implementations/Serialization/JsonSerializer.cs @@ -41,6 +41,27 @@ namespace Emby.Server.Implementations.Serialization ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); } + /// + /// Serializes to stream. + /// + /// The obj. + /// The stream. + /// obj + public void SerializeToStream(T obj, Stream stream) + { + if (obj == null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + ServiceStack.Text.JsonSerializer.SerializeToStream(obj, stream); + } + /// /// Serializes to file. /// diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 885709b0c2..c7e1461bde 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -3,7 +3,7 @@ jellyfin Exe - netcoreapp3.0 + netcoreapp2.2;netcoreapp3.0 false diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index ebeb18ea06..12ae8169d7 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -99,7 +99,7 @@ namespace Jellyfin.Server.SocketSharp name = name.Trim(HttpTrimCharacters); // First, check for correctly formed multi-line value - // Second, check for absenece of CTL characters + // Second, check for absence of CTL characters int crlf = 0; for (int i = 0; i < name.Length; ++i) { @@ -216,8 +216,13 @@ namespace Jellyfin.Server.SocketSharp { foreach (var acceptsType in acceptContentTypes) { - var contentType = HttpResultFactory.GetRealContentType(acceptsType); - acceptsAnything = acceptsAnything || contentType == "*/*"; + var contentType = acceptsType?.Split(';')[0]; + acceptsAnything = contentType.IndexOf("*/*", StringComparison.Ordinal) != -1; + + if (acceptsAnything) + { + break; + } } if (acceptsAnything) @@ -226,7 +231,7 @@ namespace Jellyfin.Server.SocketSharp { return defaultContentType; } - else if (serverDefaultContentType != null) + else { return serverDefaultContentType; } @@ -269,11 +274,11 @@ namespace Jellyfin.Server.SocketSharp private static string GetQueryStringContentType(IRequest httpReq) { - var format = httpReq.QueryString["format"]; + ReadOnlySpan format = httpReq.QueryString["format"]; if (format == null) { const int formatMaxLength = 4; - var pi = httpReq.PathInfo; + ReadOnlySpan pi = httpReq.PathInfo; if (pi == null || pi.Length <= formatMaxLength) { return null; @@ -281,7 +286,7 @@ namespace Jellyfin.Server.SocketSharp if (pi[0] == '/') { - pi = pi.Substring(1); + pi = pi.Slice(1); } format = LeftPart(pi, '/'); @@ -315,6 +320,17 @@ namespace Jellyfin.Server.SocketSharp return pos == -1 ? strVal : strVal.Substring(0, pos); } + public static ReadOnlySpan LeftPart(ReadOnlySpan strVal, char needle) + { + if (strVal == null) + { + return null; + } + + var pos = strVal.IndexOf(needle); + return pos == -1 ? strVal : strVal.Slice(0, pos); + } + public static string HandlerFactoryPath; private string pathInfo; diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 46d7c250e8..96b0aa003e 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -90,7 +90,7 @@ namespace MediaBrowser.Api.UserLibrary var options = GetDtoOptions(_authContext, request); - var ancestorIds = new List(); + var ancestorIds = Array.Empty(); var excludeFolderIds = user.Configuration.LatestItemsExcludes; if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0) @@ -99,12 +99,12 @@ namespace MediaBrowser.Api.UserLibrary .Where(i => i is Folder) .Where(i => !excludeFolderIds.Contains(i.Id.ToString("N"))) .Select(i => i.Id) - .ToList(); + .ToArray(); } var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user) { - OrderBy = new[] { ItemSortBy.DatePlayed }.Select(i => new ValueTuple(i, SortOrder.Descending)).ToArray(), + OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) }, IsResumable = true, StartIndex = request.StartIndex, Limit = request.Limit, @@ -115,7 +115,7 @@ namespace MediaBrowser.Api.UserLibrary IsVirtualItem = false, CollapseBoxSetItems = false, EnableTotalRecordCount = request.EnableTotalRecordCount, - AncestorIds = ancestorIds.ToArray(), + AncestorIds = ancestorIds, IncludeItemTypes = request.GetIncludeItemTypes(), ExcludeItemTypes = request.GetExcludeItemTypes(), SearchTerm = request.SearchTerm diff --git a/MediaBrowser.Model/Serialization/IJsonSerializer.cs b/MediaBrowser.Model/Serialization/IJsonSerializer.cs index ae0cf6f365..18f51f6525 100644 --- a/MediaBrowser.Model/Serialization/IJsonSerializer.cs +++ b/MediaBrowser.Model/Serialization/IJsonSerializer.cs @@ -14,6 +14,14 @@ namespace MediaBrowser.Model.Serialization /// obj void SerializeToStream(object obj, Stream stream); + /// + /// Serializes to stream. + /// + /// The obj. + /// The stream. + /// obj + void SerializeToStream(T obj, Stream stream); + /// /// Serializes to file. ///