From 43cf11aa358d9db117c9e9063a650460284015db Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 16:44:58 +0100 Subject: [PATCH 01/17] Change discards --- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- Jellyfin.Drawing.Skia/SkiaEncoder.cs | 2 +- Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 4eff9252e4..d74cf3be2d 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts var now = DateTime.UtcNow; - var _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); + _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); //OpenedMediaSource.Protocol = MediaProtocol.File; //OpenedMediaSource.Path = tempFile; diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index dc714ed187..5060476bad 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -282,7 +282,7 @@ namespace Jellyfin.Drawing.Skia var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack); // decode - var _ = codec.GetPixels(bitmap.Info, bitmap.GetPixels()); + _ = codec.GetPixels(bitmap.Info, bitmap.GetPixels()); origin = codec.EncodedOrigin; diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs index a44343ab2f..12591a1cde 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs @@ -83,7 +83,7 @@ namespace Jellyfin.Server.SocketSharp private void ProcessContext(HttpListenerContext context) { - var _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken)); + _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken)); } private static void LogRequest(ILogger logger, HttpListenerRequest request) From 3df8cda110a952ca529740f2b985c624c036a5f0 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 16:47:12 +0100 Subject: [PATCH 02/17] ConfigureAwait --- Jellyfin.Server/Program.cs | 8 ++++---- Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 2c177290eb..6dfabc3644 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -63,7 +63,7 @@ namespace Jellyfin.Server // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath); - await CreateLogger(appPaths); + await CreateLogger(appPaths).ConfigureAwait(false); _logger = _loggerFactory.CreateLogger("Main"); AppDomain.CurrentDomain.UnhandledException += (sender, e) @@ -115,18 +115,18 @@ namespace Jellyfin.Server new NullImageEncoder(), new NetworkManager(_loggerFactory, environmentInfo))) { - await appHost.Init(new ServiceCollection()); + await appHost.Init(new ServiceCollection()).ConfigureAwait(false); appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager); - await appHost.RunStartupTasks(); + await appHost.RunStartupTasks().ConfigureAwait(false); // TODO: read input for a stop command try { // Block main thread until shutdown - await Task.Delay(-1, _tokenSource.Token); + await Task.Delay(-1, _tokenSource.Token).ConfigureAwait(false); } catch (TaskCanceledException) { diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs index 12591a1cde..a0ffd1ccf4 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs @@ -83,7 +83,7 @@ namespace Jellyfin.Server.SocketSharp private void ProcessContext(HttpListenerContext context) { - _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken)); + _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken).ConfigureAwait(false)); } private static void LogRequest(ILogger logger, HttpListenerRequest request) From ebae7229c1dba82ec60555d951cefa90ff2df655 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 16:52:53 +0100 Subject: [PATCH 03/17] Single line comments should start with a space --- Jellyfin.Server/SocketSharp/RequestMono.cs | 8 ++++---- Jellyfin.Server/SocketSharp/SharpWebSocket.cs | 16 +--------------- .../SocketSharp/WebSocketSharpListener.cs | 4 ++-- .../SocketSharp/WebSocketSharpRequest.cs | 2 +- .../SocketSharp/WebSocketSharpResponse.cs | 12 ++++-------- 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index a8ba4cdb59..af8fe96167 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -570,10 +570,10 @@ namespace Jellyfin.Server.SocketSharp public HttpMultipart(Stream data, string b, Encoding encoding) { this.data = data; - //DB: 30/01/11: cannot set or read the Position in HttpListener in Win.NET - //var ms = new MemoryStream(32 * 1024); - //data.CopyTo(ms); - //this.data = ms; + // DB: 30/01/11: cannot set or read the Position in HttpListener in Win.NET + // var ms = new MemoryStream(32 * 1024); + // data.CopyTo(ms); + // this.data = ms; boundary = b; boundary_bytes = encoding.GetBytes(b); diff --git a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs index f371cb25a5..e7e36e31be 100644 --- a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs +++ b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs @@ -55,7 +55,7 @@ namespace Jellyfin.Server.SocketSharp void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e) { _logger.LogError("Error in SharpWebSocket: {Message}", e.Message ?? string.Empty); - //Closed?.Invoke(this, EventArgs.Empty); + // Closed?.Invoke(this, EventArgs.Empty); } void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e) @@ -67,14 +67,6 @@ namespace Jellyfin.Server.SocketSharp void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e) { - //if (!string.IsNullOrEmpty(e.Data)) - //{ - // if (OnReceive != null) - // { - // OnReceive(e.Data); - // } - // return; - //} if (OnReceiveBytes != null) { OnReceiveBytes(e.RawData); @@ -142,11 +134,5 @@ namespace Jellyfin.Server.SocketSharp /// /// The receive action. public Action OnReceiveBytes { get; set; } - - /// - /// Gets or sets the on receive. - /// - /// The on receive. - public Action OnReceive { get; set; } } } diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs index a0ffd1ccf4..4b6649217b 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs @@ -201,7 +201,7 @@ namespace Jellyfin.Server.SocketSharp } catch (ObjectDisposedException) { - //TODO Investigate and properly fix. + // TODO: Investigate and properly fix. } catch (Exception ex) { @@ -252,7 +252,7 @@ namespace Jellyfin.Server.SocketSharp Stop(); } - //release unmanaged resources here... + // release unmanaged resources here... _disposed = true; } } diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index ebeb18ea06..37fc6fe12d 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -24,7 +24,7 @@ namespace Jellyfin.Server.SocketSharp this.request = httpContext.Request; this.response = new WebSocketSharpResponse(logger, httpContext.Response, this); - //HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]); + // HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]); } private static string GetHandlerPathIfAny(string listenerUrl) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs index cabc96b237..68995a819e 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs @@ -51,7 +51,7 @@ namespace Jellyfin.Server.SocketSharp set => _response.ContentType = value; } - //public ICookies Cookies { get; set; } + // public ICookies Cookies { get; set; } public void AddHeader(string name, string value) { @@ -114,9 +114,9 @@ namespace Jellyfin.Server.SocketSharp public void SetContentLength(long contentLength) { - //you can happily set the Content-Length header in Asp.Net - //but HttpListener will complain if you do - you have to set ContentLength64 on the response. - //workaround: HttpListener throws "The parameter is incorrect" exceptions when we try to set the Content-Length header + // you can happily set the Content-Length header in Asp.Net + // but HttpListener will complain if you do - you have to set ContentLength64 on the response. + // workaround: HttpListener throws "The parameter is incorrect" exceptions when we try to set the Content-Length header _response.ContentLength64 = contentLength; } @@ -147,10 +147,6 @@ namespace Jellyfin.Server.SocketSharp { sb.Append($";domain={cookie.Domain}"); } - //else if (restrictAllCookiesToDomain != null) - //{ - // sb.Append($";domain={restrictAllCookiesToDomain}"); - //} if (cookie.Secure) { From d8b312674db11b59c90747c5d2510ed25ec40b06 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 16:54:37 +0100 Subject: [PATCH 04/17] No multiple empty lines --- Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs index 68995a819e..a4e6aac351 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs @@ -13,7 +13,6 @@ using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse; using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; using IRequest = MediaBrowser.Model.Services.IRequest; - namespace Jellyfin.Server.SocketSharp { public class WebSocketSharpResponse : IHttpResponse @@ -160,7 +159,6 @@ namespace Jellyfin.Server.SocketSharp return sb.ToString(); } - public bool SendChunked { get => _response.SendChunked; From fc59b0ab77b60cb9d06a5027ee0f2363e39fbea7 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 16:57:55 +0100 Subject: [PATCH 05/17] Disable SA1512 --- jellyfin.ruleset | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 0f8c9aa020..295a45dc94 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -7,6 +7,8 @@ + + From 637936cb9f2734df8e7c4c5838430bf5069901e6 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 16:59:30 +0100 Subject: [PATCH 06/17] Closing braces should be followed by an empty line --- Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs | 3 +++ Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs | 1 + 2 files changed, 4 insertions(+) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index 37fc6fe12d..a0f9e6d2d2 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -140,10 +140,12 @@ namespace Jellyfin.Server.SocketSharp throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); } } + if (crlf != 0) { throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); } + return name; } @@ -156,6 +158,7 @@ namespace Jellyfin.Server.SocketSharp return true; } } + return false; } diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs index a4e6aac351..6de678b86c 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs @@ -151,6 +151,7 @@ namespace Jellyfin.Server.SocketSharp { sb.Append(";Secure"); } + if (cookie.HttpOnly) { sb.Append(";HttpOnly"); From 183ef34422656468a9e145f37ed4be7a70823194 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 17:03:50 +0100 Subject: [PATCH 07/17] Do not declare visible instance fields --- Jellyfin.Server/SocketSharp/RequestMono.cs | 8 ++++++-- Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index af8fe96167..4bb2e8e190 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -127,8 +127,12 @@ namespace Jellyfin.Server.SocketSharp public string Authorization => string.IsNullOrEmpty(request.Headers["Authorization"]) ? null : request.Headers["Authorization"]; - protected bool validate_cookies, validate_query_string, validate_form; - protected bool checked_cookies, checked_query_string, checked_form; + protected bool validate_cookies { get; set; } + protected bool validate_query_string { get; set; } + protected bool validate_form { get; set; } + protected bool checked_cookies { get; set; } + protected bool checked_query_string { get; set; } + protected bool checked_form { get; set; } private static void ThrowValidationException(string name, string key, string value) { diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index a0f9e6d2d2..c5fdf6a3b0 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -447,7 +447,7 @@ namespace Jellyfin.Server.SocketSharp public string ContentType => request.ContentType; - public Encoding contentEncoding; + private Encoding contentEncoding; public Encoding ContentEncoding { get => contentEncoding ?? request.ContentEncoding; From 34af7501fa33f807aa7e721a95294b623f2d4d6c Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 17:06:32 +0100 Subject: [PATCH 08/17] Fix up CoreAppHost.cs --- Jellyfin.Server/CoreAppHost.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index a486c2a475..126cb467f9 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -18,6 +18,8 @@ namespace Jellyfin.Server public override bool CanSelfRestart => StartupOptions.RestartPath != null; + protected override bool SupportsDualModeSockets => true; + protected override void RestartInternal() => Program.Restart(); protected override IEnumerable GetAssembliesWithPartsInternal() @@ -27,8 +29,6 @@ namespace Jellyfin.Server protected override void ShutdownInternal() => Program.Shutdown(); - protected override bool SupportsDualModeSockets => true; - protected override IHttpListener CreateHttpListener() => new WebSocketSharpListener( Logger, @@ -39,7 +39,6 @@ namespace Jellyfin.Server CryptographyProvider, SupportsDualModeSockets, FileSystemManager, - EnvironmentInfo - ); + EnvironmentInfo); } } From be77e14db96b709fc0dc212258c3389a210e1af4 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 17:19:55 +0100 Subject: [PATCH 09/17] Warnings for docs --- Jellyfin.Server/Jellyfin.Server.csproj | 3 ++ Jellyfin.Server/Program.cs | 40 ++++++++++--------- Jellyfin.Server/SocketSharp/RequestMono.cs | 2 - Jellyfin.Server/SocketSharp/SharpWebSocket.cs | 1 + 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index fe1397bcbe..a6bf23f5be 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -5,11 +5,14 @@ Exe netcoreapp2.1 false + true latest + + SA1600 diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 6dfabc3644..ac5aab4609 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -57,6 +57,21 @@ namespace Jellyfin.Server errs => Task.FromResult(0)).ConfigureAwait(false); } + public static void Shutdown() + { + if (!_tokenSource.IsCancellationRequested) + { + _tokenSource.Cancel(); + } + } + + public static void Restart() + { + _restartOnShutdown = true; + + Shutdown(); + } + private static async Task StartApp(StartupOptions options) { ServerApplicationPaths appPaths = CreateApplicationPaths(options); @@ -76,6 +91,7 @@ namespace Jellyfin.Server { return; // Already shutting down } + e.Cancel = true; _logger.LogInformation("Ctrl+C, shutting down"); Environment.ExitCode = 128 + 2; @@ -89,6 +105,7 @@ namespace Jellyfin.Server { return; // Already shutting down } + _logger.LogInformation("Received a SIGTERM signal, shutting down"); Environment.ExitCode = 128 + 15; Shutdown(); @@ -102,7 +119,7 @@ namespace Jellyfin.Server SQLitePCL.Batteries_V2.Init(); // Allow all https requests - ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); + ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; } ); var fileSystem = new ManagedFileSystem(_loggerFactory, environmentInfo, null, appPaths.TempDirectory, true); @@ -146,7 +163,7 @@ namespace Jellyfin.Server /// for everything else the XDG approach is followed: /// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html /// - /// + /// StartupOptions /// ServerApplicationPaths private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options) { @@ -308,6 +325,7 @@ namespace Jellyfin.Server await rscstr.CopyToAsync(fstr).ConfigureAwait(false); } } + var configuration = new ConfigurationBuilder() .SetBasePath(appPaths.ConfigurationDirectoryPath) .AddJsonFile("logging.json") @@ -335,7 +353,7 @@ namespace Jellyfin.Server } } - public static IImageEncoder GetImageEncoder( + private static IImageEncoder GetImageEncoder( IFileSystem fileSystem, IApplicationPaths appPaths, ILocalizationManager localizationManager) @@ -376,26 +394,12 @@ namespace Jellyfin.Server { return MediaBrowser.Model.System.OperatingSystem.BSD; } + throw new Exception($"Can't resolve OS with description: '{osDescription}'"); } } } - public static void Shutdown() - { - if (!_tokenSource.IsCancellationRequested) - { - _tokenSource.Cancel(); - } - } - - public static void Restart() - { - _restartOnShutdown = true; - - Shutdown(); - } - private static void StartNewInstance(StartupOptions options) { _logger.LogInformation("Starting new instance"); diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index 4bb2e8e190..584d38bcbc 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -82,9 +82,7 @@ namespace Jellyfin.Server.SocketSharp } else { - // // We use a substream, as in 2.x we will support large uploads streamed to disk, - // var sub = new HttpPostedFile(e.Filename, e.ContentType, input, e.Start, e.Length); files[e.Name] = sub; } diff --git a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs index e7e36e31be..5b233cdf5d 100644 --- a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs +++ b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs @@ -55,6 +55,7 @@ namespace Jellyfin.Server.SocketSharp void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e) { _logger.LogError("Error in SharpWebSocket: {Message}", e.Message ?? string.Empty); + // Closed?.Invoke(this, EventArgs.Empty); } From 892787cb1a72303ffd514971d0d5ea4c30f2dcd1 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 17:25:47 +0100 Subject: [PATCH 10/17] Disable SA1130 --- jellyfin.ruleset | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 295a45dc94..25d11d7d35 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -3,6 +3,8 @@ + + From 46897aab4f85bd2ea50e0ff1ef57c0cfa8f48c67 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 17:28:04 +0100 Subject: [PATCH 11/17] More warnings --- Jellyfin.Server/SocketSharp/RequestMono.cs | 9 ++------- Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs | 7 +++++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index 584d38bcbc..9a06017501 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -431,13 +431,13 @@ namespace Jellyfin.Server.SocketSharp real = position + d; break; default: - throw new ArgumentException(nameof(origin)); + throw new ArgumentException("Unknown SeekOrigin value", nameof(origin)); } long virt = real - offset; if (virt < 0 || virt > Length) { - throw new ArgumentException(); + throw new ArgumentException("Invalid position", nameof(origin)); } position = s.Seek(real, SeekOrigin.Begin); @@ -572,11 +572,6 @@ namespace Jellyfin.Server.SocketSharp public HttpMultipart(Stream data, string b, Encoding encoding) { this.data = data; - // DB: 30/01/11: cannot set or read the Position in HttpListener in Win.NET - // var ms = new MemoryStream(32 * 1024); - // data.CopyTo(ms); - // this.data = ms; - boundary = b; boundary_bytes = encoding.GetBytes(b); buffer = new byte[boundary_bytes.Length + 2]; // CRLF or '--' diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index c5fdf6a3b0..a19ea6bf7a 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Text; using Emby.Server.Implementations.HttpServer; @@ -69,9 +70,11 @@ namespace Jellyfin.Server.SocketSharp public string UserHostAddress => request.UserHostAddress; - public string XForwardedFor => string.IsNullOrEmpty(request.Headers["X-Forwarded-For"]) ? null : request.Headers["X-Forwarded-For"]; + public string XForwardedFor + => string.IsNullOrEmpty(request.Headers["X-Forwarded-For"]) ? null : request.Headers["X-Forwarded-For"]; - public int? XForwardedPort => string.IsNullOrEmpty(request.Headers["X-Forwarded-Port"]) ? (int?)null : int.Parse(request.Headers["X-Forwarded-Port"]); + public int? XForwardedPort + => string.IsNullOrEmpty(request.Headers["X-Forwarded-Port"]) ? (int?)null : int.Parse(request.Headers["X-Forwarded-Port"], CultureInfo.InvariantCulture); public string XForwardedProtocol => string.IsNullOrEmpty(request.Headers["X-Forwarded-Proto"]) ? null : request.Headers["X-Forwarded-Proto"]; From 2cb747651b134313ffdca930af38b07002a38992 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 17:36:10 +0100 Subject: [PATCH 12/17] Correctly dispose WebSocketSharpListener --- .../SocketSharp/WebSocketSharpListener.cs | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs index 4b6649217b..90bd981f5b 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs @@ -223,38 +223,39 @@ namespace Jellyfin.Server.SocketSharp public Task Stop() { _disposeCancellationTokenSource.Cancel(); - - if (_listener != null) - { - _listener.Close(); - } + _listener?.Close(); return Task.CompletedTask; } + /// + /// Releases the unmanaged resources and disposes of the managed resources used. + /// public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } private bool _disposed; - private readonly object _disposeLock = new object(); + + /// + /// Releases the unmanaged resources and disposes of the managed resources used. + /// + /// Whether or not the managed resources should be disposed protected virtual void Dispose(bool disposing) { - if (_disposed) return; - - lock (_disposeLock) + if (_disposed) { - if (_disposed) return; - - if (disposing) - { - Stop(); - } + return; + } - // release unmanaged resources here... - _disposed = true; + if (disposing) + { + Stop().GetAwaiter().GetResult(); } + + _disposed = true; } } } From 8b04fe76332e70ab579f0f9ac84012ef310e73cf Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 18:37:44 +0100 Subject: [PATCH 13/17] More fixes --- Jellyfin.Server/SocketSharp/RequestMono.cs | 37 ++++++++++++------- Jellyfin.Server/SocketSharp/SharpWebSocket.cs | 27 +++++++++----- .../SocketSharp/WebSocketSharpListener.cs | 22 ++++++++--- .../SocketSharp/WebSocketSharpRequest.cs | 13 ++++++- 4 files changed, 70 insertions(+), 29 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index 9a06017501..dd38b058b1 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -13,7 +13,7 @@ namespace Jellyfin.Server.SocketSharp { internal static string GetParameter(string header, string attr) { - int ap = header.IndexOf(attr); + int ap = header.IndexOf(attr, StringComparison.Ordinal); if (ap == -1) { return null; @@ -140,8 +140,12 @@ namespace Jellyfin.Server.SocketSharp v = v.Substring(0, 16) + "...\""; } - string msg = string.Format("A potentially dangerous Request.{0} value was " + - "detected from the client ({1}={2}).", name, key, v); + string msg = string.Format( + CultureInfo.InvariantCulture, + "A potentially dangerous Request.{0} value was detected from the client ({1}={2}).", + name, + key, + v); throw new Exception(msg); } @@ -258,6 +262,7 @@ namespace Jellyfin.Server.SocketSharp value.Append((char)c); } } + if (c == -1) { AddRawKeyValue(form, key, value); @@ -273,6 +278,7 @@ namespace Jellyfin.Server.SocketSharp key.Append((char)c); } } + if (c == -1) { AddRawKeyValue(form, key, value); @@ -310,6 +316,7 @@ namespace Jellyfin.Server.SocketSharp result.Append(key); result.Append('='); } + result.Append(pair.Value); } @@ -493,11 +500,6 @@ namespace Jellyfin.Server.SocketSharp public Stream InputStream => stream; } - private class Helpers - { - public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture; - } - internal static class StrUtils { public static bool StartsWith(string str1, string str2, bool ignore_case) @@ -535,12 +537,17 @@ namespace Jellyfin.Server.SocketSharp public class Element { - public string ContentType; - public string Name; - public string Filename; - public Encoding Encoding; - public long Start; - public long Length; + public string ContentType { get; set; } + + public string Name { get; set; } + + public string Filename { get; set; } + + public Encoding Encoding { get; set; } + + public long Start { get; set; } + + public long Length { get; set; } public override string ToString() { @@ -597,6 +604,7 @@ namespace Jellyfin.Server.SocketSharp { break; } + got_cr = b == CR; sb.Append((char)b); } @@ -797,6 +805,7 @@ namespace Jellyfin.Server.SocketSharp c = data.ReadByte(); continue; } + data.Position = retval + 2; if (got_cr) { diff --git a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs index 5b233cdf5d..6eee4cd12e 100644 --- a/Jellyfin.Server/SocketSharp/SharpWebSocket.cs +++ b/Jellyfin.Server/SocketSharp/SharpWebSocket.cs @@ -24,6 +24,7 @@ namespace Jellyfin.Server.SocketSharp private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + private bool _disposed = false; public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger) { @@ -40,9 +41,9 @@ namespace Jellyfin.Server.SocketSharp _logger = logger; WebSocket = socket; - socket.OnMessage += socket_OnMessage; - socket.OnClose += socket_OnClose; - socket.OnError += socket_OnError; + socket.OnMessage += OnSocketMessage; + socket.OnClose += OnSocketClose; + socket.OnError += OnSocketError; WebSocket.ConnectAsServer(); } @@ -52,21 +53,21 @@ namespace Jellyfin.Server.SocketSharp return _taskCompletionSource.Task; } - void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e) + private void OnSocketError(object sender, SocketHttpListener.ErrorEventArgs e) { _logger.LogError("Error in SharpWebSocket: {Message}", e.Message ?? string.Empty); // Closed?.Invoke(this, EventArgs.Empty); } - void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e) + private void OnSocketClose(object sender, SocketHttpListener.CloseEventArgs e) { _taskCompletionSource.TrySetResult(true); Closed?.Invoke(this, EventArgs.Empty); } - void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e) + private void OnSocketMessage(object sender, SocketHttpListener.MessageEventArgs e) { if (OnReceiveBytes != null) { @@ -110,6 +111,7 @@ namespace Jellyfin.Server.SocketSharp public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// @@ -118,16 +120,23 @@ namespace Jellyfin.Server.SocketSharp /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { + if (_disposed) + { + return; + } + if (dispose) { - WebSocket.OnMessage -= socket_OnMessage; - WebSocket.OnClose -= socket_OnClose; - WebSocket.OnError -= socket_OnError; + WebSocket.OnMessage -= OnSocketMessage; + WebSocket.OnClose -= OnSocketClose; + WebSocket.OnError -= OnSocketError; _cancellationTokenSource.Cancel(); WebSocket.Close(); } + + _disposed = true; } /// diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs index 90bd981f5b..58c4d38a24 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs @@ -34,9 +34,16 @@ namespace Jellyfin.Server.SocketSharp private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); private CancellationToken _disposeCancellationToken; - public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IStreamHelper streamHelper, - INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, - bool enableDualMode, IFileSystem fileSystem, IEnvironmentInfo environment) + public WebSocketSharpListener( + ILogger logger, + X509Certificate certificate, + IStreamHelper streamHelper, + INetworkManager networkManager, + ISocketFactory socketFactory, + ICryptoProvider cryptoProvider, + bool enableDualMode, + IFileSystem fileSystem, + IEnvironmentInfo environment) { _logger = logger; _certificate = certificate; @@ -61,7 +68,9 @@ namespace Jellyfin.Server.SocketSharp public void Start(IEnumerable urlPrefixes) { if (_listener == null) + { _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _streamHelper, _fileSystem, _environment); + } _listener.EnableDualMode = _enableDualMode; @@ -90,8 +99,11 @@ namespace Jellyfin.Server.SocketSharp { var url = request.Url.ToString(); - logger.LogInformation("{0} {1}. UserAgent: {2}", - request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty); + logger.LogInformation( + "{0} {1}. UserAgent: {2}", + request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, + url, + request.UserAgent ?? string.Empty); } private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index a19ea6bf7a..cbce7d4571 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -42,7 +42,7 @@ namespace Jellyfin.Server.SocketSharp } var startHostUrl = listenerUrl.Substring(pos + "://".Length); - var endPos = startHostUrl.IndexOf('/'); + var endPos = startHostUrl.IndexOf('/', StringComparison.Ordinal); if (endPos == -1) { return null; @@ -110,6 +110,7 @@ namespace Jellyfin.Server.SocketSharp switch (crlf) { case 0: + { if (c == '\r') { crlf = 1; @@ -124,23 +125,31 @@ namespace Jellyfin.Server.SocketSharp { throw new ArgumentException("net_WebHeaderInvalidControlChars"); } + break; + } case 1: + { if (c == '\n') { crlf = 2; break; } + throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); + } case 2: + { if (c == ' ' || c == '\t') { crlf = 0; break; } + throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); + } } } @@ -349,6 +358,7 @@ namespace Jellyfin.Server.SocketSharp this.pathInfo = System.Net.WebUtility.UrlDecode(pathInfo); this.pathInfo = NormalizePathInfo(pathInfo, mode); } + return this.pathInfo; } } @@ -508,6 +518,7 @@ namespace Jellyfin.Server.SocketSharp i++; } } + return httpFiles; } } From e620bb95123f76c6eea92226a1e4c10d094ea65a Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 18:47:26 +0100 Subject: [PATCH 14/17] Remove more doc warnings --- Jellyfin.Server/Jellyfin.Server.csproj | 2 +- jellyfin.ruleset | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index a6bf23f5be..1f2287a758 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -12,7 +12,7 @@ latest - SA1600 + SA1600;CS1591 diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 25d11d7d35..4381349ca6 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -14,4 +14,8 @@ + + + + From cb9e50b2eae1cff7f21e893dee309a7ff629bd31 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Feb 2019 18:55:23 +0100 Subject: [PATCH 15/17] Reorder elements --- Jellyfin.Server/SocketSharp/RequestMono.cs | 97 ++++++++++--------- .../SocketSharp/WebSocketSharpResponse.cs | 7 +- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index dd38b058b1..fe8e8242a6 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -185,6 +185,7 @@ namespace Jellyfin.Server.SocketSharp for (int idx = 1; idx < len; idx++) { char next = val[idx]; + // See http://secunia.com/advisories/14325 if (current == '<' || current == '\xff1c') { @@ -556,15 +557,23 @@ namespace Jellyfin.Server.SocketSharp } } + private const byte LF = (byte)'\n'; + + private const byte CR = (byte)'\r'; + private Stream data; + private string boundary; - private byte[] boundary_bytes; + + private byte[] boundaryBytes; + private byte[] buffer; - private bool at_eof; + + private bool atEof; + private Encoding encoding; - private StringBuilder sb; - private const byte LF = (byte)'\n', CR = (byte)'\r'; + private StringBuilder sb; // See RFC 2046 // In the case of multipart entities, in which one or more different @@ -580,12 +589,48 @@ namespace Jellyfin.Server.SocketSharp { this.data = data; boundary = b; - boundary_bytes = encoding.GetBytes(b); - buffer = new byte[boundary_bytes.Length + 2]; // CRLF or '--' + boundaryBytes = encoding.GetBytes(b); + buffer = new byte[boundaryBytes.Length + 2]; // CRLF or '--' this.encoding = encoding; sb = new StringBuilder(); } + public Element ReadNextElement() + { + if (atEof || ReadBoundary()) + { + return null; + } + + var elem = new Element(); + string header; + while ((header = ReadHeaders()) != null) + { + if (StrUtils.StartsWith(header, "Content-Disposition:", true)) + { + elem.Name = GetContentDispositionAttribute(header, "name"); + elem.Filename = StripPath(GetContentDispositionAttributeWithEncoding(header, "filename")); + } + else if (StrUtils.StartsWith(header, "Content-Type:", true)) + { + elem.ContentType = header.Substring("Content-Type:".Length).Trim(); + elem.Encoding = GetEncoding(elem.ContentType); + } + } + + long start = 0; + start = data.Position; + elem.Start = start; + long pos = MoveToNextBoundary(); + if (pos == -1) + { + return null; + } + + elem.Length = pos - start; + return elem; + } + private string ReadLine() { // CRLF or LF are ok as line endings. @@ -774,7 +819,7 @@ namespace Jellyfin.Server.SocketSharp return -1; } - if (!CompareBytes(boundary_bytes, buffer)) + if (!CompareBytes(boundaryBytes, buffer)) { state = 0; data.Position = retval + 2; @@ -790,7 +835,7 @@ namespace Jellyfin.Server.SocketSharp if (buffer[bl - 2] == '-' && buffer[bl - 1] == '-') { - at_eof = true; + atEof = true; } else if (buffer[bl - 2] != CR || buffer[bl - 1] != LF) { @@ -824,42 +869,6 @@ namespace Jellyfin.Server.SocketSharp return retval; } - public Element ReadNextElement() - { - if (at_eof || ReadBoundary()) - { - return null; - } - - var elem = new Element(); - string header; - while ((header = ReadHeaders()) != null) - { - if (StrUtils.StartsWith(header, "Content-Disposition:", true)) - { - elem.Name = GetContentDispositionAttribute(header, "name"); - elem.Filename = StripPath(GetContentDispositionAttributeWithEncoding(header, "filename")); - } - else if (StrUtils.StartsWith(header, "Content-Type:", true)) - { - elem.ContentType = header.Substring("Content-Type:".Length).Trim(); - elem.Encoding = GetEncoding(elem.ContentType); - } - } - - long start = 0; - start = data.Position; - elem.Start = start; - long pos = MoveToNextBoundary(); - if (pos == -1) - { - return null; - } - - elem.Length = pos - start; - return elem; - } - private static string StripPath(string path) { if (path == null || path.Length == 0) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs index 6de678b86c..56e5c73d61 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs @@ -18,6 +18,7 @@ namespace Jellyfin.Server.SocketSharp public class WebSocketSharpResponse : IHttpResponse { private readonly ILogger _logger; + private readonly HttpListenerResponse _response; public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request) @@ -29,7 +30,9 @@ namespace Jellyfin.Server.SocketSharp } public IRequest Request { get; private set; } + public Dictionary Items { get; private set; } + public object OriginalResponse => _response; public int StatusCode @@ -50,7 +53,7 @@ namespace Jellyfin.Server.SocketSharp set => _response.ContentType = value; } - // public ICookies Cookies { get; set; } + public QueryParamCollection Headers => _response.Headers; public void AddHeader(string name, string value) { @@ -63,8 +66,6 @@ namespace Jellyfin.Server.SocketSharp _response.AddHeader(name, value); } - public QueryParamCollection Headers => _response.Headers; - public string GetHeader(string name) { return _response.Headers[name]; From 3947f2315dea8b7e390e219f188d0ecf3f5ee2d2 Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 16 Feb 2019 00:05:47 +0100 Subject: [PATCH 16/17] Update Jellyfin.Server/Jellyfin.Server.csproj Co-Authored-By: Bond-009 --- Jellyfin.Server/Jellyfin.Server.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 1f2287a758..bd670df527 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -11,7 +11,7 @@ latest - + SA1600;CS1591 From 18e1d03a89b7fe3ddba925f81b153d0f0cd1973c Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sat, 16 Feb 2019 00:42:09 +0100 Subject: [PATCH 17/17] Comments --- Jellyfin.Server/SocketSharp/RequestMono.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index fe8e8242a6..24cf994eaf 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -445,7 +445,7 @@ namespace Jellyfin.Server.SocketSharp long virt = real - offset; if (virt < 0 || virt > Length) { - throw new ArgumentException("Invalid position", nameof(origin)); + throw new ArgumentException("Invalid position", nameof(d)); } position = s.Seek(real, SeekOrigin.Begin); @@ -618,8 +618,7 @@ namespace Jellyfin.Server.SocketSharp } } - long start = 0; - start = data.Position; + long start = data.Position; elem.Start = start; long pos = MoveToNextBoundary(); if (pos == -1)