Browse Source

Merge pull request #885 from Bond-009/warn

More warning fixes
Vasily 6 years ago
parent
commit
b7ae044e65

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs

@@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
 
 
             var now = DateTime.UtcNow;
             var now = DateTime.UtcNow;
 
 
-            var _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
+            _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
 
 
             //OpenedMediaSource.Protocol = MediaProtocol.File;
             //OpenedMediaSource.Protocol = MediaProtocol.File;
             //OpenedMediaSource.Path = tempFile;
             //OpenedMediaSource.Path = tempFile;

+ 1 - 1
Jellyfin.Drawing.Skia/SkiaEncoder.cs

@@ -282,7 +282,7 @@ namespace Jellyfin.Drawing.Skia
                     var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
                     var bitmap = new SKBitmap(codec.Info.Width, codec.Info.Height, !requiresTransparencyHack);
 
 
                     // decode
                     // decode
-                    var _ = codec.GetPixels(bitmap.Info, bitmap.GetPixels());
+                    _ = codec.GetPixels(bitmap.Info, bitmap.GetPixels());
 
 
                     origin = codec.EncodedOrigin;
                     origin = codec.EncodedOrigin;
 
 

+ 3 - 4
Jellyfin.Server/CoreAppHost.cs

@@ -18,6 +18,8 @@ namespace Jellyfin.Server
 
 
         public override bool CanSelfRestart => StartupOptions.RestartPath != null;
         public override bool CanSelfRestart => StartupOptions.RestartPath != null;
 
 
+        protected override bool SupportsDualModeSockets => true;
+
         protected override void RestartInternal() => Program.Restart();
         protected override void RestartInternal() => Program.Restart();
 
 
         protected override IEnumerable<Assembly> GetAssembliesWithPartsInternal()
         protected override IEnumerable<Assembly> GetAssembliesWithPartsInternal()
@@ -27,8 +29,6 @@ namespace Jellyfin.Server
 
 
         protected override void ShutdownInternal() => Program.Shutdown();
         protected override void ShutdownInternal() => Program.Shutdown();
 
 
-        protected override bool SupportsDualModeSockets => true;
-
         protected override IHttpListener CreateHttpListener()
         protected override IHttpListener CreateHttpListener()
             => new WebSocketSharpListener(
             => new WebSocketSharpListener(
                 Logger,
                 Logger,
@@ -39,7 +39,6 @@ namespace Jellyfin.Server
                 CryptographyProvider,
                 CryptographyProvider,
                 SupportsDualModeSockets,
                 SupportsDualModeSockets,
                 FileSystemManager,
                 FileSystemManager,
-                EnvironmentInfo
-            );
+                EnvironmentInfo);
     }
     }
 }
 }

+ 3 - 0
Jellyfin.Server/Jellyfin.Server.csproj

@@ -5,11 +5,14 @@
     <OutputType>Exe</OutputType>
     <OutputType>Exe</OutputType>
     <TargetFramework>netcoreapp2.1</TargetFramework>
     <TargetFramework>netcoreapp2.1</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <PropertyGroup>
   <PropertyGroup>
     <!-- We need C# 7.1 for async main-->
     <!-- We need C# 7.1 for async main-->
     <LangVersion>latest</LangVersion>
     <LangVersion>latest</LangVersion>
+    <!-- Disable documentation warnings (for now) -->
+    <NoWarn>SA1600;CS1591</NoWarn>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 26 - 22
Jellyfin.Server/Program.cs

@@ -57,13 +57,28 @@ namespace Jellyfin.Server
                     errs => Task.FromResult(0)).ConfigureAwait(false);
                     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)
         private static async Task StartApp(StartupOptions options)
         {
         {
             ServerApplicationPaths appPaths = CreateApplicationPaths(options);
             ServerApplicationPaths appPaths = CreateApplicationPaths(options);
 
 
             // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
             // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
             Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);
             Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);
-            await CreateLogger(appPaths);
+            await CreateLogger(appPaths).ConfigureAwait(false);
             _logger = _loggerFactory.CreateLogger("Main");
             _logger = _loggerFactory.CreateLogger("Main");
 
 
             AppDomain.CurrentDomain.UnhandledException += (sender, e)
             AppDomain.CurrentDomain.UnhandledException += (sender, e)
@@ -76,6 +91,7 @@ namespace Jellyfin.Server
                 {
                 {
                     return; // Already shutting down
                     return; // Already shutting down
                 }
                 }
+
                 e.Cancel = true;
                 e.Cancel = true;
                 _logger.LogInformation("Ctrl+C, shutting down");
                 _logger.LogInformation("Ctrl+C, shutting down");
                 Environment.ExitCode = 128 + 2;
                 Environment.ExitCode = 128 + 2;
@@ -89,6 +105,7 @@ namespace Jellyfin.Server
                 {
                 {
                     return; // Already shutting down
                     return; // Already shutting down
                 }
                 }
+
                 _logger.LogInformation("Received a SIGTERM signal, shutting down");
                 _logger.LogInformation("Received a SIGTERM signal, shutting down");
                 Environment.ExitCode = 128 + 15;
                 Environment.ExitCode = 128 + 15;
                 Shutdown();
                 Shutdown();
@@ -102,7 +119,7 @@ namespace Jellyfin.Server
             SQLitePCL.Batteries_V2.Init();
             SQLitePCL.Batteries_V2.Init();
 
 
             // Allow all https requests
             // 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);
             var fileSystem = new ManagedFileSystem(_loggerFactory, environmentInfo, null, appPaths.TempDirectory, true);
 
 
@@ -115,18 +132,18 @@ namespace Jellyfin.Server
                 new NullImageEncoder(),
                 new NullImageEncoder(),
                 new NetworkManager(_loggerFactory, environmentInfo)))
                 new NetworkManager(_loggerFactory, environmentInfo)))
             {
             {
-                await appHost.Init(new ServiceCollection());
+                await appHost.Init(new ServiceCollection()).ConfigureAwait(false);
 
 
                 appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager);
                 appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager);
 
 
-                await appHost.RunStartupTasks();
+                await appHost.RunStartupTasks().ConfigureAwait(false);
 
 
                 // TODO: read input for a stop command
                 // TODO: read input for a stop command
 
 
                 try
                 try
                 {
                 {
                     // Block main thread until shutdown
                     // Block main thread until shutdown
-                    await Task.Delay(-1, _tokenSource.Token);
+                    await Task.Delay(-1, _tokenSource.Token).ConfigureAwait(false);
                 }
                 }
                 catch (TaskCanceledException)
                 catch (TaskCanceledException)
                 {
                 {
@@ -146,7 +163,7 @@ namespace Jellyfin.Server
         /// for everything else the XDG approach is followed:
         /// for everything else the XDG approach is followed:
         /// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
         /// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
         /// </summary>
         /// </summary>
-        /// <param name="options"></param>
+        /// <param name="options">StartupOptions</param>
         /// <returns>ServerApplicationPaths</returns>
         /// <returns>ServerApplicationPaths</returns>
         private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
         private static ServerApplicationPaths CreateApplicationPaths(StartupOptions options)
         {
         {
@@ -308,6 +325,7 @@ namespace Jellyfin.Server
                         await rscstr.CopyToAsync(fstr).ConfigureAwait(false);
                         await rscstr.CopyToAsync(fstr).ConfigureAwait(false);
                     }
                     }
                 }
                 }
+
                 var configuration = new ConfigurationBuilder()
                 var configuration = new ConfigurationBuilder()
                     .SetBasePath(appPaths.ConfigurationDirectoryPath)
                     .SetBasePath(appPaths.ConfigurationDirectoryPath)
                     .AddJsonFile("logging.json")
                     .AddJsonFile("logging.json")
@@ -335,7 +353,7 @@ namespace Jellyfin.Server
             }
             }
         }
         }
 
 
-        public static IImageEncoder GetImageEncoder(
+        private static IImageEncoder GetImageEncoder(
             IFileSystem fileSystem,
             IFileSystem fileSystem,
             IApplicationPaths appPaths,
             IApplicationPaths appPaths,
             ILocalizationManager localizationManager)
             ILocalizationManager localizationManager)
@@ -376,26 +394,12 @@ namespace Jellyfin.Server
                         {
                         {
                             return MediaBrowser.Model.System.OperatingSystem.BSD;
                             return MediaBrowser.Model.System.OperatingSystem.BSD;
                         }
                         }
+
                         throw new Exception($"Can't resolve OS with description: '{osDescription}'");
                         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)
         private static void StartNewInstance(StartupOptions options)
         {
         {
             _logger.LogInformation("Starting new instance");
             _logger.LogInformation("Starting new instance");

+ 83 - 69
Jellyfin.Server/SocketSharp/RequestMono.cs

@@ -13,7 +13,7 @@ namespace Jellyfin.Server.SocketSharp
     {
     {
         internal static string GetParameter(string header, string attr)
         internal static string GetParameter(string header, string attr)
         {
         {
-            int ap = header.IndexOf(attr);
+            int ap = header.IndexOf(attr, StringComparison.Ordinal);
             if (ap == -1)
             if (ap == -1)
             {
             {
                 return null;
                 return null;
@@ -82,9 +82,7 @@ namespace Jellyfin.Server.SocketSharp
                     }
                     }
                     else
                     else
                     {
                     {
-                        //
                         // We use a substream, as in 2.x we will support large uploads streamed to disk,
                         // 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);
                         var sub = new HttpPostedFile(e.Filename, e.ContentType, input, e.Start, e.Length);
                         files[e.Name] = sub;
                         files[e.Name] = sub;
                     }
                     }
@@ -127,8 +125,12 @@ namespace Jellyfin.Server.SocketSharp
 
 
         public string Authorization => string.IsNullOrEmpty(request.Headers["Authorization"]) ? null : request.Headers["Authorization"];
         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)
         private static void ThrowValidationException(string name, string key, string value)
         {
         {
@@ -138,8 +140,12 @@ namespace Jellyfin.Server.SocketSharp
                 v = v.Substring(0, 16) + "...\"";
                 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);
             throw new Exception(msg);
         }
         }
@@ -179,6 +185,7 @@ namespace Jellyfin.Server.SocketSharp
             for (int idx = 1; idx < len; idx++)
             for (int idx = 1; idx < len; idx++)
             {
             {
                 char next = val[idx];
                 char next = val[idx];
+
                 // See http://secunia.com/advisories/14325
                 // See http://secunia.com/advisories/14325
                 if (current == '<' || current == '\xff1c')
                 if (current == '<' || current == '\xff1c')
                 {
                 {
@@ -256,6 +263,7 @@ namespace Jellyfin.Server.SocketSharp
                                         value.Append((char)c);
                                         value.Append((char)c);
                                     }
                                     }
                                 }
                                 }
+
                                 if (c == -1)
                                 if (c == -1)
                                 {
                                 {
                                     AddRawKeyValue(form, key, value);
                                     AddRawKeyValue(form, key, value);
@@ -271,6 +279,7 @@ namespace Jellyfin.Server.SocketSharp
                                 key.Append((char)c);
                                 key.Append((char)c);
                             }
                             }
                         }
                         }
+
                         if (c == -1)
                         if (c == -1)
                         {
                         {
                             AddRawKeyValue(form, key, value);
                             AddRawKeyValue(form, key, value);
@@ -308,6 +317,7 @@ namespace Jellyfin.Server.SocketSharp
                         result.Append(key);
                         result.Append(key);
                         result.Append('=');
                         result.Append('=');
                     }
                     }
+
                     result.Append(pair.Value);
                     result.Append(pair.Value);
                 }
                 }
 
 
@@ -429,13 +439,13 @@ namespace Jellyfin.Server.SocketSharp
                             real = position + d;
                             real = position + d;
                             break;
                             break;
                         default:
                         default:
-                            throw new ArgumentException(nameof(origin));
+                            throw new ArgumentException("Unknown SeekOrigin value", nameof(origin));
                     }
                     }
 
 
                     long virt = real - offset;
                     long virt = real - offset;
                     if (virt < 0 || virt > Length)
                     if (virt < 0 || virt > Length)
                     {
                     {
-                        throw new ArgumentException();
+                        throw new ArgumentException("Invalid position", nameof(d));
                     }
                     }
 
 
                     position = s.Seek(real, SeekOrigin.Begin);
                     position = s.Seek(real, SeekOrigin.Begin);
@@ -491,11 +501,6 @@ namespace Jellyfin.Server.SocketSharp
             public Stream InputStream => stream;
             public Stream InputStream => stream;
         }
         }
 
 
-        private class Helpers
-        {
-            public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture;
-        }
-
         internal static class StrUtils
         internal static class StrUtils
         {
         {
             public static bool StartsWith(string str1, string str2, bool ignore_case)
             public static bool StartsWith(string str1, string str2, bool ignore_case)
@@ -533,12 +538,17 @@ namespace Jellyfin.Server.SocketSharp
 
 
             public class Element
             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()
                 public override string ToString()
                 {
                 {
@@ -547,15 +557,23 @@ namespace Jellyfin.Server.SocketSharp
                 }
                 }
             }
             }
 
 
+            private const byte LF = (byte)'\n';
+
+            private const byte CR = (byte)'\r';
+
             private Stream data;
             private Stream data;
+
             private string boundary;
             private string boundary;
-            private byte[] boundary_bytes;
+
+            private byte[] boundaryBytes;
+
             private byte[] buffer;
             private byte[] buffer;
-            private bool at_eof;
+
+            private bool atEof;
+
             private Encoding encoding;
             private Encoding encoding;
-            private StringBuilder sb;
 
 
-            private const byte LF = (byte)'\n', CR = (byte)'\r';
+            private StringBuilder sb;
 
 
             // See RFC 2046
             // See RFC 2046
             // In the case of multipart entities, in which one or more different
             // In the case of multipart entities, in which one or more different
@@ -570,18 +588,48 @@ namespace Jellyfin.Server.SocketSharp
             public HttpMultipart(Stream data, string b, Encoding encoding)
             public HttpMultipart(Stream data, string b, Encoding encoding)
             {
             {
                 this.data = data;
                 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 = 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;
                 this.encoding = encoding;
                 sb = new StringBuilder();
                 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 = data.Position;
+                elem.Start = start;
+                long pos = MoveToNextBoundary();
+                if (pos == -1)
+                {
+                    return null;
+                }
+
+                elem.Length = pos - start;
+                return elem;
+            }
+
             private string ReadLine()
             private string ReadLine()
             {
             {
                 // CRLF or LF are ok as line endings.
                 // CRLF or LF are ok as line endings.
@@ -600,6 +648,7 @@ namespace Jellyfin.Server.SocketSharp
                     {
                     {
                         break;
                         break;
                     }
                     }
+
                     got_cr = b == CR;
                     got_cr = b == CR;
                     sb.Append((char)b);
                     sb.Append((char)b);
                 }
                 }
@@ -769,7 +818,7 @@ namespace Jellyfin.Server.SocketSharp
                             return -1;
                             return -1;
                         }
                         }
 
 
-                        if (!CompareBytes(boundary_bytes, buffer))
+                        if (!CompareBytes(boundaryBytes, buffer))
                         {
                         {
                             state = 0;
                             state = 0;
                             data.Position = retval + 2;
                             data.Position = retval + 2;
@@ -785,7 +834,7 @@ namespace Jellyfin.Server.SocketSharp
 
 
                         if (buffer[bl - 2] == '-' && buffer[bl - 1] == '-')
                         if (buffer[bl - 2] == '-' && buffer[bl - 1] == '-')
                         {
                         {
-                            at_eof = true;
+                            atEof = true;
                         }
                         }
                         else if (buffer[bl - 2] != CR || buffer[bl - 1] != LF)
                         else if (buffer[bl - 2] != CR || buffer[bl - 1] != LF)
                         {
                         {
@@ -800,6 +849,7 @@ namespace Jellyfin.Server.SocketSharp
                             c = data.ReadByte();
                             c = data.ReadByte();
                             continue;
                             continue;
                         }
                         }
+
                         data.Position = retval + 2;
                         data.Position = retval + 2;
                         if (got_cr)
                         if (got_cr)
                         {
                         {
@@ -818,42 +868,6 @@ namespace Jellyfin.Server.SocketSharp
                 return retval;
                 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)
             private static string StripPath(string path)
             {
             {
                 if (path == null || path.Length == 0)
                 if (path == null || path.Length == 0)

+ 20 - 24
Jellyfin.Server/SocketSharp/SharpWebSocket.cs

@@ -24,6 +24,7 @@ namespace Jellyfin.Server.SocketSharp
 
 
         private TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
         private TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>();
         private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
         private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
+        private bool _disposed = false;
 
 
         public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger)
         public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger)
         {
         {
@@ -40,9 +41,9 @@ namespace Jellyfin.Server.SocketSharp
             _logger = logger;
             _logger = logger;
             WebSocket = socket;
             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();
             WebSocket.ConnectAsServer();
         }
         }
@@ -52,29 +53,22 @@ namespace Jellyfin.Server.SocketSharp
             return _taskCompletionSource.Task;
             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);
             _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)
+        private void OnSocketClose(object sender, SocketHttpListener.CloseEventArgs e)
         {
         {
             _taskCompletionSource.TrySetResult(true);
             _taskCompletionSource.TrySetResult(true);
 
 
             Closed?.Invoke(this, EventArgs.Empty);
             Closed?.Invoke(this, EventArgs.Empty);
         }
         }
 
 
-        void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e)
+        private void OnSocketMessage(object sender, SocketHttpListener.MessageEventArgs e)
         {
         {
-            //if (!string.IsNullOrEmpty(e.Data))
-            //{
-            //    if (OnReceive != null)
-            //    {
-            //        OnReceive(e.Data);
-            //    }
-            //    return;
-            //}
             if (OnReceiveBytes != null)
             if (OnReceiveBytes != null)
             {
             {
                 OnReceiveBytes(e.RawData);
                 OnReceiveBytes(e.RawData);
@@ -117,6 +111,7 @@ namespace Jellyfin.Server.SocketSharp
         public void Dispose()
         public void Dispose()
         {
         {
             Dispose(true);
             Dispose(true);
+            GC.SuppressFinalize(this);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -125,16 +120,23 @@ namespace Jellyfin.Server.SocketSharp
         /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
         /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
         protected virtual void Dispose(bool dispose)
         protected virtual void Dispose(bool dispose)
         {
         {
+            if (_disposed)
+            {
+                return;
+            }
+
             if (dispose)
             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();
                 _cancellationTokenSource.Cancel();
 
 
                 WebSocket.Close();
                 WebSocket.Close();
             }
             }
+
+            _disposed = true;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -142,11 +144,5 @@ namespace Jellyfin.Server.SocketSharp
         /// </summary>
         /// </summary>
         /// <value>The receive action.</value>
         /// <value>The receive action.</value>
         public Action<byte[]> OnReceiveBytes { get; set; }
         public Action<byte[]> OnReceiveBytes { get; set; }
-
-        /// <summary>
-        /// Gets or sets the on receive.
-        /// </summary>
-        /// <value>The on receive.</value>
-        public Action<string> OnReceive { get; set; }
     }
     }
 }
 }

+ 37 - 24
Jellyfin.Server/SocketSharp/WebSocketSharpListener.cs

@@ -34,9 +34,16 @@ namespace Jellyfin.Server.SocketSharp
         private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
         private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
         private CancellationToken _disposeCancellationToken;
         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;
             _logger = logger;
             _certificate = certificate;
             _certificate = certificate;
@@ -61,7 +68,9 @@ namespace Jellyfin.Server.SocketSharp
         public void Start(IEnumerable<string> urlPrefixes)
         public void Start(IEnumerable<string> urlPrefixes)
         {
         {
             if (_listener == null)
             if (_listener == null)
+            {
                 _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _streamHelper, _fileSystem, _environment);
                 _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _streamHelper, _fileSystem, _environment);
+            }
 
 
             _listener.EnableDualMode = _enableDualMode;
             _listener.EnableDualMode = _enableDualMode;
 
 
@@ -83,15 +92,18 @@ namespace Jellyfin.Server.SocketSharp
 
 
         private void ProcessContext(HttpListenerContext context)
         private void ProcessContext(HttpListenerContext context)
         {
         {
-            var _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken));
+            _ = Task.Run(async () => await InitTask(context, _disposeCancellationToken).ConfigureAwait(false));
         }
         }
 
 
         private static void LogRequest(ILogger logger, HttpListenerRequest request)
         private static void LogRequest(ILogger logger, HttpListenerRequest request)
         {
         {
             var url = request.Url.ToString();
             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)
         private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken)
@@ -201,7 +213,7 @@ namespace Jellyfin.Server.SocketSharp
             }
             }
             catch (ObjectDisposedException)
             catch (ObjectDisposedException)
             {
             {
-                //TODO Investigate and properly fix.
+                // TODO: Investigate and properly fix.
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
@@ -223,38 +235,39 @@ namespace Jellyfin.Server.SocketSharp
         public Task Stop()
         public Task Stop()
         {
         {
             _disposeCancellationTokenSource.Cancel();
             _disposeCancellationTokenSource.Cancel();
-
-            if (_listener != null)
-            {
-                _listener.Close();
-            }
+            _listener?.Close();
 
 
             return Task.CompletedTask;
             return Task.CompletedTask;
         }
         }
 
 
+        /// <summary>
+        /// Releases the unmanaged resources and disposes of the managed resources used.
+        /// </summary>
         public void Dispose()
         public void Dispose()
         {
         {
             Dispose(true);
             Dispose(true);
+            GC.SuppressFinalize(this);
         }
         }
 
 
         private bool _disposed;
         private bool _disposed;
-        private readonly object _disposeLock = new object();
+
+        /// <summary>
+        /// Releases the unmanaged resources and disposes of the managed resources used.
+        /// </summary>
+        /// <param name="disposing">Whether or not the managed resources should be disposed</param>
         protected virtual void Dispose(bool disposing)
         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;
         }
         }
     }
     }
 }
 }

+ 22 - 5
Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;
 using Emby.Server.Implementations.HttpServer;
 using Emby.Server.Implementations.HttpServer;
@@ -24,7 +25,7 @@ namespace Jellyfin.Server.SocketSharp
             this.request = httpContext.Request;
             this.request = httpContext.Request;
             this.response = new WebSocketSharpResponse(logger, httpContext.Response, this);
             this.response = new WebSocketSharpResponse(logger, httpContext.Response, this);
 
 
-            //HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
+            // HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
         }
         }
 
 
         private static string GetHandlerPathIfAny(string listenerUrl)
         private static string GetHandlerPathIfAny(string listenerUrl)
@@ -41,7 +42,7 @@ namespace Jellyfin.Server.SocketSharp
             }
             }
 
 
             var startHostUrl = listenerUrl.Substring(pos + "://".Length);
             var startHostUrl = listenerUrl.Substring(pos + "://".Length);
-            var endPos = startHostUrl.IndexOf('/');
+            var endPos = startHostUrl.IndexOf('/', StringComparison.Ordinal);
             if (endPos == -1)
             if (endPos == -1)
             {
             {
                 return null;
                 return null;
@@ -69,9 +70,11 @@ namespace Jellyfin.Server.SocketSharp
 
 
         public string UserHostAddress => request.UserHostAddress;
         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"];
         public string XForwardedProtocol => string.IsNullOrEmpty(request.Headers["X-Forwarded-Proto"]) ? null : request.Headers["X-Forwarded-Proto"];
 
 
@@ -107,6 +110,7 @@ namespace Jellyfin.Server.SocketSharp
                 switch (crlf)
                 switch (crlf)
                 {
                 {
                     case 0:
                     case 0:
+                    {
                         if (c == '\r')
                         if (c == '\r')
                         {
                         {
                             crlf = 1;
                             crlf = 1;
@@ -121,29 +125,39 @@ namespace Jellyfin.Server.SocketSharp
                         {
                         {
                             throw new ArgumentException("net_WebHeaderInvalidControlChars");
                             throw new ArgumentException("net_WebHeaderInvalidControlChars");
                         }
                         }
+
                         break;
                         break;
+                    }
 
 
                     case 1:
                     case 1:
+                    {
                         if (c == '\n')
                         if (c == '\n')
                         {
                         {
                             crlf = 2;
                             crlf = 2;
                             break;
                             break;
                         }
                         }
+
                         throw new ArgumentException("net_WebHeaderInvalidCRLFChars");
                         throw new ArgumentException("net_WebHeaderInvalidCRLFChars");
+                    }
 
 
                     case 2:
                     case 2:
+                    {
                         if (c == ' ' || c == '\t')
                         if (c == ' ' || c == '\t')
                         {
                         {
                             crlf = 0;
                             crlf = 0;
                             break;
                             break;
                         }
                         }
+
                         throw new ArgumentException("net_WebHeaderInvalidCRLFChars");
                         throw new ArgumentException("net_WebHeaderInvalidCRLFChars");
+                    }
                 }
                 }
             }
             }
+
             if (crlf != 0)
             if (crlf != 0)
             {
             {
                 throw new ArgumentException("net_WebHeaderInvalidCRLFChars");
                 throw new ArgumentException("net_WebHeaderInvalidCRLFChars");
             }
             }
+
             return name;
             return name;
         }
         }
 
 
@@ -156,6 +170,7 @@ namespace Jellyfin.Server.SocketSharp
                     return true;
                     return true;
                 }
                 }
             }
             }
+
             return false;
             return false;
         }
         }
 
 
@@ -343,6 +358,7 @@ namespace Jellyfin.Server.SocketSharp
                     this.pathInfo = System.Net.WebUtility.UrlDecode(pathInfo);
                     this.pathInfo = System.Net.WebUtility.UrlDecode(pathInfo);
                     this.pathInfo = NormalizePathInfo(pathInfo, mode);
                     this.pathInfo = NormalizePathInfo(pathInfo, mode);
                 }
                 }
+
                 return this.pathInfo;
                 return this.pathInfo;
             }
             }
         }
         }
@@ -444,7 +460,7 @@ namespace Jellyfin.Server.SocketSharp
 
 
         public string ContentType => request.ContentType;
         public string ContentType => request.ContentType;
 
 
-        public Encoding contentEncoding;
+        private Encoding contentEncoding;
         public Encoding ContentEncoding
         public Encoding ContentEncoding
         {
         {
             get => contentEncoding ?? request.ContentEncoding;
             get => contentEncoding ?? request.ContentEncoding;
@@ -502,6 +518,7 @@ namespace Jellyfin.Server.SocketSharp
                         i++;
                         i++;
                     }
                     }
                 }
                 }
+
                 return httpFiles;
                 return httpFiles;
             }
             }
         }
         }

+ 8 - 12
Jellyfin.Server/SocketSharp/WebSocketSharpResponse.cs

@@ -13,12 +13,12 @@ using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
 using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
 using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
 using IRequest = MediaBrowser.Model.Services.IRequest;
 using IRequest = MediaBrowser.Model.Services.IRequest;
 
 
-
 namespace Jellyfin.Server.SocketSharp
 namespace Jellyfin.Server.SocketSharp
 {
 {
     public class WebSocketSharpResponse : IHttpResponse
     public class WebSocketSharpResponse : IHttpResponse
     {
     {
         private readonly ILogger _logger;
         private readonly ILogger _logger;
+
         private readonly HttpListenerResponse _response;
         private readonly HttpListenerResponse _response;
 
 
         public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request)
         public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request)
@@ -30,7 +30,9 @@ namespace Jellyfin.Server.SocketSharp
         }
         }
 
 
         public IRequest Request { get; private set; }
         public IRequest Request { get; private set; }
+
         public Dictionary<string, object> Items { get; private set; }
         public Dictionary<string, object> Items { get; private set; }
+
         public object OriginalResponse => _response;
         public object OriginalResponse => _response;
 
 
         public int StatusCode
         public int StatusCode
@@ -51,7 +53,7 @@ namespace Jellyfin.Server.SocketSharp
             set => _response.ContentType = value;
             set => _response.ContentType = value;
         }
         }
 
 
-        //public ICookies Cookies { get; set; }
+        public QueryParamCollection Headers => _response.Headers;
 
 
         public void AddHeader(string name, string value)
         public void AddHeader(string name, string value)
         {
         {
@@ -64,8 +66,6 @@ namespace Jellyfin.Server.SocketSharp
             _response.AddHeader(name, value);
             _response.AddHeader(name, value);
         }
         }
 
 
-        public QueryParamCollection Headers => _response.Headers;
-
         public string GetHeader(string name)
         public string GetHeader(string name)
         {
         {
             return _response.Headers[name];
             return _response.Headers[name];
@@ -114,9 +114,9 @@ namespace Jellyfin.Server.SocketSharp
 
 
         public void SetContentLength(long contentLength)
         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;
             _response.ContentLength64 = contentLength;
         }
         }
 
 
@@ -147,15 +147,12 @@ namespace Jellyfin.Server.SocketSharp
             {
             {
                 sb.Append($";domain={cookie.Domain}");
                 sb.Append($";domain={cookie.Domain}");
             }
             }
-            //else if (restrictAllCookiesToDomain != null)
-            //{
-            //    sb.Append($";domain={restrictAllCookiesToDomain}");
-            //}
 
 
             if (cookie.Secure)
             if (cookie.Secure)
             {
             {
                 sb.Append(";Secure");
                 sb.Append(";Secure");
             }
             }
+
             if (cookie.HttpOnly)
             if (cookie.HttpOnly)
             {
             {
                 sb.Append(";HttpOnly");
                 sb.Append(";HttpOnly");
@@ -164,7 +161,6 @@ namespace Jellyfin.Server.SocketSharp
             return sb.ToString();
             return sb.ToString();
         }
         }
 
 
-
         public bool SendChunked
         public bool SendChunked
         {
         {
             get => _response.SendChunked;
             get => _response.SendChunked;

+ 8 - 0
jellyfin.ruleset

@@ -3,11 +3,19 @@
   <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
   <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
     <!-- disable warning SA1101: Prefix local calls with 'this.' -->
     <!-- disable warning SA1101: Prefix local calls with 'this.' -->
     <Rule Id="SA1101" Action="None" />
     <Rule Id="SA1101" Action="None" />
+    <!-- disable warning SA1130: Use lambda syntax -->
+    <Rule Id="SA1130" Action="None" />
     <!-- disable warning SA1200: 'using' directive must appear within a namespace declaration -->
     <!-- disable warning SA1200: 'using' directive must appear within a namespace declaration -->
     <Rule Id="SA1200" Action="None" />
     <Rule Id="SA1200" Action="None" />
     <!-- disable warning SA1309: Fields must not begin with an underscore -->
     <!-- disable warning SA1309: Fields must not begin with an underscore -->
     <Rule Id="SA1309" Action="None" />
     <Rule Id="SA1309" Action="None" />
+    <!-- disable warning SA1512: Single-line comments must not be followed by blank line -->
+    <Rule Id="SA1512" Action="None" />
     <!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
     <!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
     <Rule Id="SA1633" Action="None" />
     <Rule Id="SA1633" Action="None" />
   </Rules>
   </Rules>
+  <Rules AnalyzerId="Microsoft.CodeAnalysis.FxCopAnalyzers" RuleNamespace="Microsoft.Design">
+    <!-- disable warning CA1054: Change the type of parameter url from string to System.Uri -->
+    <Rule Id="CA1054" Action="None" />
+  </Rules>
 </RuleSet>
 </RuleSet>