Less string allocations

pull/848/head
Bond_009 5 years ago committed by Bond-009
parent da9418c1b2
commit 8d98885cda

@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary> /// </summary>
private IHasHeaders GetHttpResult(IRequest requestContext, Stream content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null) private IHasHeaders GetHttpResult(IRequest requestContext, Stream content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null)
{ {
var result = new StreamWriter(content, contentType, _logger); var result = new StreamWriter(content, contentType);
if (responseHeaders == null) if (responseHeaders == null)
{ {
@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.HttpServer
content = Array.Empty<byte>(); content = Array.Empty<byte>();
} }
result = new StreamWriter(content, contentType, contentLength, _logger); result = new StreamWriter(content, contentType, contentLength);
} }
else else
{ {
@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary<string, string>(); responseHeaders = new Dictionary<string, string>();
} }
if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires)) if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _))
{ {
responseHeaders["Expires"] = "-1"; responseHeaders["Expires"] = "-1";
} }
@ -175,7 +175,7 @@ namespace Emby.Server.Implementations.HttpServer
bytes = Array.Empty<byte>(); bytes = Array.Empty<byte>();
} }
result = new StreamWriter(bytes, contentType, contentLength, _logger); result = new StreamWriter(bytes, contentType, contentLength);
} }
else else
{ {
@ -187,7 +187,7 @@ namespace Emby.Server.Implementations.HttpServer
responseHeaders = new Dictionary<string, string>(); responseHeaders = new Dictionary<string, string>();
} }
if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires)) if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _))
{ {
responseHeaders["Expires"] = "-1"; responseHeaders["Expires"] = "-1";
} }
@ -277,9 +277,9 @@ namespace Emby.Server.Implementations.HttpServer
private object ToOptimizedResultInternal<T>(IRequest request, T dto, IDictionary<string, string> responseHeaders = null) private object ToOptimizedResultInternal<T>(IRequest request, T dto, IDictionary<string, string> responseHeaders = null)
{ {
var contentType = request.ResponseContentType; var contentType = request.ResponseContentType?.Split(';')[0];
switch (GetRealContentType(contentType)) switch (contentType)
{ {
case "application/xml": case "application/xml":
case "text/xml": case "text/xml":
@ -333,13 +333,13 @@ namespace Emby.Server.Implementations.HttpServer
if (isHeadRequest) if (isHeadRequest)
{ {
var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength, _logger); var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength);
AddResponseHeaders(result, responseHeaders); AddResponseHeaders(result, responseHeaders);
return result; return result;
} }
else else
{ {
var result = new StreamWriter(content, contentType, contentLength, _logger); var result = new StreamWriter(content, contentType, contentLength);
AddResponseHeaders(result, responseHeaders); AddResponseHeaders(result, responseHeaders);
return result; return result;
} }
@ -348,13 +348,19 @@ namespace Emby.Server.Implementations.HttpServer
private byte[] Compress(byte[] bytes, string compressionType) private byte[] Compress(byte[] bytes, string compressionType)
{ {
if (string.Equals(compressionType, "br", StringComparison.OrdinalIgnoreCase)) if (string.Equals(compressionType, "br", StringComparison.OrdinalIgnoreCase))
{
return CompressBrotli(bytes); return CompressBrotli(bytes);
}
if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase)) if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase))
{
return Deflate(bytes); return Deflate(bytes);
}
if (string.Equals(compressionType, "gzip", StringComparison.OrdinalIgnoreCase)) if (string.Equals(compressionType, "gzip", StringComparison.OrdinalIgnoreCase))
{
return GZip(bytes); return GZip(bytes);
}
throw new NotSupportedException(compressionType); 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) private static string SerializeToXmlString(object from)
{ {
using (var ms = new MemoryStream()) 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, OnComplete = options.OnComplete,
OnError = options.OnError OnError = options.OnError

@ -14,8 +14,6 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary> /// </summary>
public class StreamWriter : IAsyncStreamWriter, IHasHeaders public class StreamWriter : IAsyncStreamWriter, IHasHeaders
{ {
private ILogger Logger { get; set; }
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary> /// <summary>
@ -45,7 +43,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param> /// <param name="contentType">Type of the content.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public StreamWriter(Stream source, string contentType, ILogger logger) public StreamWriter(Stream source, string contentType)
{ {
if (string.IsNullOrEmpty(contentType)) if (string.IsNullOrEmpty(contentType))
{ {
@ -53,7 +51,6 @@ namespace Emby.Server.Implementations.HttpServer
} }
SourceStream = source; SourceStream = source;
Logger = logger;
Headers["Content-Type"] = contentType; Headers["Content-Type"] = contentType;
@ -69,7 +66,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param> /// <param name="contentType">Type of the content.</param>
/// <param name="logger">The logger.</param> /// <param name="logger">The logger.</param>
public StreamWriter(byte[] source, string contentType, int contentLength, ILogger logger) public StreamWriter(byte[] source, string contentType, int contentLength)
{ {
if (string.IsNullOrEmpty(contentType)) if (string.IsNullOrEmpty(contentType))
{ {
@ -77,7 +74,6 @@ namespace Emby.Server.Implementations.HttpServer
} }
SourceBytes = source; SourceBytes = source;
Logger = logger;
Headers["Content-Type"] = contentType; Headers["Content-Type"] = contentType;

@ -184,7 +184,7 @@ namespace Emby.Server.Implementations.LiveTv
public QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken) public QueryResult<BaseItem> 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); var topFolder = GetInternalLiveTvFolder(cancellationToken);

@ -41,6 +41,27 @@ namespace Emby.Server.Implementations.Serialization
ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream); ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream);
} }
/// <summary>
/// Serializes to stream.
/// </summary>
/// <param name="obj">The obj.</param>
/// <param name="stream">The stream.</param>
/// <exception cref="ArgumentNullException">obj</exception>
public void SerializeToStream<T>(T obj, Stream stream)
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
ServiceStack.Text.JsonSerializer.SerializeToStream<T>(obj, stream);
}
/// <summary> /// <summary>
/// Serializes to file. /// Serializes to file.
/// </summary> /// </summary>

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<AssemblyName>jellyfin</AssemblyName> <AssemblyName>jellyfin</AssemblyName>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework> <TargetFrameworks>netcoreapp2.2;netcoreapp3.0</TargetFrameworks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup> </PropertyGroup>

@ -99,7 +99,7 @@ namespace Jellyfin.Server.SocketSharp
name = name.Trim(HttpTrimCharacters); name = name.Trim(HttpTrimCharacters);
// First, check for correctly formed multi-line value // 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; int crlf = 0;
for (int i = 0; i < name.Length; ++i) for (int i = 0; i < name.Length; ++i)
{ {
@ -216,8 +216,13 @@ namespace Jellyfin.Server.SocketSharp
{ {
foreach (var acceptsType in acceptContentTypes) foreach (var acceptsType in acceptContentTypes)
{ {
var contentType = HttpResultFactory.GetRealContentType(acceptsType); var contentType = acceptsType?.Split(';')[0];
acceptsAnything = acceptsAnything || contentType == "*/*"; acceptsAnything = contentType.IndexOf("*/*", StringComparison.Ordinal) != -1;
if (acceptsAnything)
{
break;
}
} }
if (acceptsAnything) if (acceptsAnything)
@ -226,7 +231,7 @@ namespace Jellyfin.Server.SocketSharp
{ {
return defaultContentType; return defaultContentType;
} }
else if (serverDefaultContentType != null) else
{ {
return serverDefaultContentType; return serverDefaultContentType;
} }
@ -269,11 +274,11 @@ namespace Jellyfin.Server.SocketSharp
private static string GetQueryStringContentType(IRequest httpReq) private static string GetQueryStringContentType(IRequest httpReq)
{ {
var format = httpReq.QueryString["format"]; ReadOnlySpan<char> format = httpReq.QueryString["format"];
if (format == null) if (format == null)
{ {
const int formatMaxLength = 4; const int formatMaxLength = 4;
var pi = httpReq.PathInfo; ReadOnlySpan<char> pi = httpReq.PathInfo;
if (pi == null || pi.Length <= formatMaxLength) if (pi == null || pi.Length <= formatMaxLength)
{ {
return null; return null;
@ -281,7 +286,7 @@ namespace Jellyfin.Server.SocketSharp
if (pi[0] == '/') if (pi[0] == '/')
{ {
pi = pi.Substring(1); pi = pi.Slice(1);
} }
format = LeftPart(pi, '/'); format = LeftPart(pi, '/');
@ -315,6 +320,17 @@ namespace Jellyfin.Server.SocketSharp
return pos == -1 ? strVal : strVal.Substring(0, pos); return pos == -1 ? strVal : strVal.Substring(0, pos);
} }
public static ReadOnlySpan<char> LeftPart(ReadOnlySpan<char> 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; public static string HandlerFactoryPath;
private string pathInfo; private string pathInfo;

@ -90,7 +90,7 @@ namespace MediaBrowser.Api.UserLibrary
var options = GetDtoOptions(_authContext, request); var options = GetDtoOptions(_authContext, request);
var ancestorIds = new List<Guid>(); var ancestorIds = Array.Empty<Guid>();
var excludeFolderIds = user.Configuration.LatestItemsExcludes; var excludeFolderIds = user.Configuration.LatestItemsExcludes;
if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0) if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0)
@ -99,12 +99,12 @@ namespace MediaBrowser.Api.UserLibrary
.Where(i => i is Folder) .Where(i => i is Folder)
.Where(i => !excludeFolderIds.Contains(i.Id.ToString("N"))) .Where(i => !excludeFolderIds.Contains(i.Id.ToString("N")))
.Select(i => i.Id) .Select(i => i.Id)
.ToList(); .ToArray();
} }
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user) var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{ {
OrderBy = new[] { ItemSortBy.DatePlayed }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(), OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) },
IsResumable = true, IsResumable = true,
StartIndex = request.StartIndex, StartIndex = request.StartIndex,
Limit = request.Limit, Limit = request.Limit,
@ -115,7 +115,7 @@ namespace MediaBrowser.Api.UserLibrary
IsVirtualItem = false, IsVirtualItem = false,
CollapseBoxSetItems = false, CollapseBoxSetItems = false,
EnableTotalRecordCount = request.EnableTotalRecordCount, EnableTotalRecordCount = request.EnableTotalRecordCount,
AncestorIds = ancestorIds.ToArray(), AncestorIds = ancestorIds,
IncludeItemTypes = request.GetIncludeItemTypes(), IncludeItemTypes = request.GetIncludeItemTypes(),
ExcludeItemTypes = request.GetExcludeItemTypes(), ExcludeItemTypes = request.GetExcludeItemTypes(),
SearchTerm = request.SearchTerm SearchTerm = request.SearchTerm

@ -14,6 +14,14 @@ namespace MediaBrowser.Model.Serialization
/// <exception cref="ArgumentNullException">obj</exception> /// <exception cref="ArgumentNullException">obj</exception>
void SerializeToStream(object obj, Stream stream); void SerializeToStream(object obj, Stream stream);
/// <summary>
/// Serializes to stream.
/// </summary>
/// <param name="obj">The obj.</param>
/// <param name="stream">The stream.</param>
/// <exception cref="ArgumentNullException">obj</exception>
void SerializeToStream<T>(T obj, Stream stream);
/// <summary> /// <summary>
/// Serializes to file. /// Serializes to file.
/// </summary> /// </summary>

Loading…
Cancel
Save