diff options
Diffstat (limited to 'MediaBrowser.Server.Mono')
| -rw-r--r-- | MediaBrowser.Server.Mono/EmbyServer.csproj | 55 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/ImageEncoderHelper.cs | 51 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/MonoAppHost.cs | 102 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/Native/MonoFileSystem.cs | 23 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/Native/PowerManagement.cs | 21 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/Program.cs | 326 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs | 15 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/Properties/launchSettings.json | 7 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/SocketSharp/HttpFile.cs | 14 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/SocketSharp/RequestMono.cs | 807 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/SocketSharp/SharpWebSocket.cs | 159 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs | 262 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpRequest.cs | 556 | ||||
| -rw-r--r-- | MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpResponse.cs | 196 |
14 files changed, 0 insertions, 2594 deletions
diff --git a/MediaBrowser.Server.Mono/EmbyServer.csproj b/MediaBrowser.Server.Mono/EmbyServer.csproj deleted file mode 100644 index 480b422bc..000000000 --- a/MediaBrowser.Server.Mono/EmbyServer.csproj +++ /dev/null @@ -1,55 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <OutputType>Exe</OutputType> - <AssemblyName>jellyfin</AssemblyName> - <TargetFramework>netcoreapp2.1</TargetFramework> - <GenerateAssemblyInfo>false</GenerateAssemblyInfo> - </PropertyGroup> - - <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> - <DebugType>None</DebugType> - <RuntimeIdentifiers>ubuntu.16.04-x64</RuntimeIdentifiers> - </PropertyGroup> - - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> - <PlatformTarget>AnyCPU</PlatformTarget> - </PropertyGroup> - - <ItemGroup> - <PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" /> - <PackageReference Include="SkiaSharp" Version="1.68.0" /> - <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="1.1.11" /> - <PackageReference Include="SQLitePCLRaw.core" Version="1.1.11" /> - <PackageReference Include="SQLitePCLRaw.provider.sqlite3.netstandard11" Version="1.1.11" /> - </ItemGroup> - - <ItemGroup> - <ProjectReference Include="..\Emby.IsoMounting\IsoMounter\IsoMounter.csproj" /> - <ProjectReference Include="..\BDInfo\BDInfo.csproj" /> - <ProjectReference Include="..\DvdLib\DvdLib.csproj" /> - <ProjectReference Include="..\Emby.Dlna\Emby.Dlna.csproj" /> - <ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj" /> - <ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj" /> - <ProjectReference Include="..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" /> - <ProjectReference Include="..\MediaBrowser.WebDashboard\MediaBrowser.WebDashboard.csproj" /> - <ProjectReference Include="..\MediaBrowser.Providers\MediaBrowser.Providers.csproj" /> - <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> - <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" /> - <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" /> - <ProjectReference Include="..\MediaBrowser.Api\MediaBrowser.Api.csproj" /> - <ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj" /> - <ProjectReference Include="..\MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj" /> - <ProjectReference Include="..\Mono.Nat\Mono.Nat.csproj" /> - <ProjectReference Include="..\OpenSubtitlesHandler\OpenSubtitlesHandler.csproj" /> - <ProjectReference Include="..\RSSDP\RSSDP.csproj" /> - <ProjectReference Include="..\Emby.Drawing.Skia\Emby.Drawing.Skia.csproj" /> - <ProjectReference Include="..\Emby.Drawing.ImageMagick\Emby.Drawing.ImageMagick.csproj" /> - <ProjectReference Include="..\SocketHttpListener\SocketHttpListener.csproj" /> - </ItemGroup> - - <ItemGroup> - <Compile Include="..\SharedVersion.cs" /> - </ItemGroup> - -</Project> diff --git a/MediaBrowser.Server.Mono/ImageEncoderHelper.cs b/MediaBrowser.Server.Mono/ImageEncoderHelper.cs deleted file mode 100644 index 49955ad65..000000000 --- a/MediaBrowser.Server.Mono/ImageEncoderHelper.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Emby.Drawing; -using Emby.Drawing.ImageMagick; -using Emby.Server.Implementations; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Drawing; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using Emby.Drawing.Skia; -using MediaBrowser.Model.System; -using MediaBrowser.Model.Globalization; - -namespace MediaBrowser.Server.Startup.Common -{ - public class ImageEncoderHelper - { - public static IImageEncoder GetImageEncoder(ILogger logger, - ILogManager logManager, - IFileSystem fileSystem, - StartupOptions startupOptions, - Func<IHttpClient> httpClient, - IApplicationPaths appPaths, - IEnvironmentInfo environment, - ILocalizationManager localizationManager) - { - if (!startupOptions.ContainsOption("-enablegdi")) - { - try - { - return new SkiaEncoder(logManager.GetLogger("Skia"), appPaths, httpClient, fileSystem, localizationManager); - } - catch (Exception ex) - { - logger.Info("Skia not available. Will try next image processor. {0}", ex.Message); - } - - try - { - return new ImageMagickEncoder(logManager.GetLogger("ImageMagick"), appPaths, httpClient, fileSystem, environment); - } - catch - { - logger.Info("ImageMagick not available. Will try next image processor."); - } - } - - return new NullImageEncoder(); - } - } -} diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs deleted file mode 100644 index 576eb5c68..000000000 --- a/MediaBrowser.Server.Mono/MonoAppHost.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -//using Emby.Server.CinemaMode; -using Emby.Server.Implementations; -using Emby.Server.Implementations.Library; -using Emby.Server.Implementations.HttpServer; -using Emby.Server.Implementations.Net; -using MediaBrowser.Controller.Connect; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Sync; -using IsoMounter; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; - -namespace MediaBrowser.Server.Mono -{ - public class MonoAppHost : ApplicationHost - { - public MonoAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager) - { - } - - public override bool CanSelfRestart - { - get - { - // A restart script must be provided - return StartupOptions.ContainsOption("-restartpath"); - } - } - - //protected override ISyncManager CreateSyncManager() - //{ - // return new SyncManager(); - //} - - protected override void RestartInternal() - { - MainClass.Restart(); - } - - protected override List<Assembly> GetAssembliesWithPartsInternal() - { - var list = new List<Assembly>(); - - list.Add(GetType().Assembly); - - return list; - } - - protected override void ShutdownInternal() - { - MainClass.Shutdown(); - } - - protected override bool SupportsDualModeSockets - { - get - { - return GetMonoVersion() >= new Version(4, 6); - } - } - - private static Version GetMonoVersion() - { - Type type = Type.GetType("Mono.Runtime"); - if (type != null) - { - MethodInfo displayName = type.GetTypeInfo().GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); - var displayNameValue = displayName.Invoke(null, null).ToString().Trim().Split(' ')[0]; - - Version version; - if (Version.TryParse(displayNameValue, out version)) - { - return version; - } - } - - return new Version(1, 0); - } - - protected override IHttpListener CreateHttpListener() - { - return new EmbyServer.SocketSharp.WebSocketSharpListener(LogManager.GetLogger("HttpServer"), - Certificate, - StreamHelper, - TextEncoding, - NetworkManager, - SocketFactory, - CryptographyProvider, - SupportsDualModeSockets, - FileSystemManager, - EnvironmentInfo); - } - - } -} diff --git a/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs b/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs deleted file mode 100644 index 2fd95ab82..000000000 --- a/MediaBrowser.Server.Mono/Native/MonoFileSystem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Emby.Server.Implementations.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.System; -using Mono.Unix.Native; - -namespace MediaBrowser.Server.Mono.Native -{ - public class MonoFileSystem : ManagedFileSystem - { - public MonoFileSystem(ILogger logger, IEnvironmentInfo environment, string defaultDirectory, string tempPath, bool enableSeperateFileAndDirectoryQueries) - : base(logger, environment,defaultDirectory, tempPath, enableSeperateFileAndDirectoryQueries) - { - } - - public override void SetExecutable(string path) - { - // Linux: File permission to 666, and user's execute bit - Logger.Info("Syscall.chmod {0} FilePermissions.DEFFILEMODE | FilePermissions.S_IRWXU | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH", path); - - Syscall.chmod(path, FilePermissions.DEFFILEMODE | FilePermissions.S_IRWXU | FilePermissions.S_IXGRP | FilePermissions.S_IXOTH); - } - } -} diff --git a/MediaBrowser.Server.Mono/Native/PowerManagement.cs b/MediaBrowser.Server.Mono/Native/PowerManagement.cs deleted file mode 100644 index 219a69d65..000000000 --- a/MediaBrowser.Server.Mono/Native/PowerManagement.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using MediaBrowser.Model.System; - -namespace MediaBrowser.Server.Mono.Native -{ - public class PowerManagement : IPowerManagement - { - public void PreventSystemStandby() - { - } - - public void AllowSystemStandby() - { - } - - public void ScheduleWake(DateTime wakeTimeUtc, string displayName) - { - // nothing to Do - } - } -} diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs deleted file mode 100644 index 887a9545f..000000000 --- a/MediaBrowser.Server.Mono/Program.cs +++ /dev/null @@ -1,326 +0,0 @@ -using MediaBrowser.Model.Logging; -using MediaBrowser.Server.Mono.Native; -using MediaBrowser.Server.Startup.Common; -using System; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Security; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Emby.Drawing; -using Emby.Server.Implementations; -using Emby.Server.Implementations.EnvironmentInfo; -using Emby.Server.Implementations.IO; -using Emby.Server.Implementations.Logging; -using Emby.Server.Implementations.Networking; -using MediaBrowser.Controller; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.System; -using Mono.Unix.Native; -using ILogger = MediaBrowser.Model.Logging.ILogger; -using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate; -using System.Threading; -using InteropServices = System.Runtime.InteropServices; - -namespace MediaBrowser.Server.Mono -{ - public class MainClass - { - private static ILogger _logger; - private static IFileSystem FileSystem; - private static IServerApplicationPaths _appPaths; - private static ILogManager _logManager; - - private static readonly TaskCompletionSource<bool> ApplicationTaskCompletionSource = new TaskCompletionSource<bool>(); - private static bool _restartOnShutdown; - - public static void Main(string[] args) - { - var applicationPath = Assembly.GetEntryAssembly().Location; - - SetSqliteProvider(); - - var options = new StartupOptions(Environment.GetCommandLineArgs()); - - // Allow this to be specified on the command line. - var customProgramDataPath = options.GetOption("-programdata"); - - var appPaths = CreateApplicationPaths(applicationPath, customProgramDataPath); - _appPaths = appPaths; - - using (var logManager = new SimpleLogManager(appPaths.LogDirectoryPath, "server")) - { - _logManager = logManager; - - var task = logManager.ReloadLogger(LogSeverity.Debug, CancellationToken.None); - Task.WaitAll(task); - logManager.AddConsoleOutput(); - - var logger = _logger = logManager.GetLogger("Main"); - - ApplicationHost.LogEnvironmentInfo(logger, appPaths, true); - - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - - RunApplication(appPaths, logManager, options); - - _logger.Info("Disposing app host"); - - if (_restartOnShutdown) - { - StartNewInstance(options); - } - } - } - - private static void SetSqliteProvider() - { - // SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3()); - //SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_sqlite3()); - SQLitePCL.Batteries_V2.Init(); - } - - private static ServerApplicationPaths CreateApplicationPaths(string applicationPath, string programDataPath) - { - if (string.IsNullOrEmpty(programDataPath)) - { - if (InteropServices.RuntimeInformation.IsOSPlatform(InteropServices.OSPlatform.Windows)) - { - programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - } - else - { - // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. - programDataPath = Environment.GetEnvironmentVariable("XDG_DATA_HOME"); - // If $XDG_DATA_HOME is either not set or empty, $HOME/.local/share should be used. - if (string.IsNullOrEmpty(programDataPath)){ - programDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share"); - } - } - programDataPath = Path.Combine(programDataPath, "jellyfin"); - } - - var appFolderPath = Path.GetDirectoryName(applicationPath); - - return new ServerApplicationPaths(programDataPath, appFolderPath, appFolderPath); - } - - private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options) - { - // Allow all https requests - ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); - - var environmentInfo = GetEnvironmentInfo(); - - var fileSystem = new ManagedFileSystem(logManager.GetLogger("FileSystem"), environmentInfo, null, appPaths.TempDirectory, true); - - FileSystem = fileSystem; - - using (var appHost = new MonoAppHost(appPaths, - logManager, - options, - fileSystem, - new PowerManagement(), - "embyserver-mono_{version}.zip", - environmentInfo, - new NullImageEncoder(), - new SystemEvents(logManager.GetLogger("SystemEvents")), - new NetworkManager(logManager.GetLogger("NetworkManager"), environmentInfo))) - { - if (options.ContainsOption("-v")) - { - Console.WriteLine(appHost.ApplicationVersion.ToString()); - return; - } - - Console.WriteLine("appHost.Init"); - - appHost.Init(); - - appHost.ImageProcessor.ImageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => appHost.HttpClient, appPaths, environmentInfo, appHost.LocalizationManager); - - Console.WriteLine("Running startup tasks"); - - var task = appHost.RunStartupTasks(); - Task.WaitAll(task); - - task = ApplicationTaskCompletionSource.Task; - - Task.WaitAll(task); - } - } - - private static MonoEnvironmentInfo GetEnvironmentInfo() - { - var info = new MonoEnvironmentInfo(); - - var uname = GetUnixName(); - - var sysName = uname.sysname ?? string.Empty; - - if (string.Equals(sysName, "Darwin", StringComparison.OrdinalIgnoreCase)) - { - info.OperatingSystem = Model.System.OperatingSystem.OSX; - } - else if (string.Equals(sysName, "Linux", StringComparison.OrdinalIgnoreCase)) - { - info.OperatingSystem = Model.System.OperatingSystem.Linux; - } - else if (string.Equals(sysName, "BSD", StringComparison.OrdinalIgnoreCase)) - { - info.OperatingSystem = Model.System.OperatingSystem.BSD; - } - - var archX86 = new Regex("(i|I)[3-6]86"); - - if (archX86.IsMatch(uname.machine)) - { - info.SystemArchitecture = Architecture.X86; - } - else if (string.Equals(uname.machine, "x86_64", StringComparison.OrdinalIgnoreCase)) - { - info.SystemArchitecture = Architecture.X64; - } - else if (uname.machine.StartsWith("arm", StringComparison.OrdinalIgnoreCase)) - { - info.SystemArchitecture = Architecture.Arm; - } - else if (System.Environment.Is64BitOperatingSystem) - { - info.SystemArchitecture = Architecture.X64; - } - else - { - info.SystemArchitecture = Architecture.X86; - } - - return info; - } - - private static Uname _unixName; - - private static Uname GetUnixName() - { - if (_unixName == null) - { - var uname = new Uname(); - try - { - Utsname utsname; - var callResult = Syscall.uname(out utsname); - if (callResult == 0) - { - uname.sysname = utsname.sysname ?? string.Empty; - uname.machine = utsname.machine ?? string.Empty; - } - - } - catch (Exception ex) - { - _logger.ErrorException("Error getting unix name", ex); - } - _unixName = uname; - } - return _unixName; - } - - public class Uname - { - public string sysname = string.Empty; - public string machine = string.Empty; - } - - /// <summary> - /// Handles the UnhandledException event of the CurrentDomain control. - /// </summary> - /// <param name="sender">The source of the event.</param> - /// <param name="e">The <see cref="UnhandledExceptionEventArgs"/> instance containing the event data.</param> - static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { - var exception = (Exception)e.ExceptionObject; - - new UnhandledExceptionWriter(_appPaths, _logger, _logManager, FileSystem, new ConsoleLogger()).Log(exception); - - if (!Debugger.IsAttached) - { - var message = LogHelper.GetLogMessage(exception).ToString(); - - if (message.IndexOf("InotifyWatcher", StringComparison.OrdinalIgnoreCase) == -1 && - message.IndexOf("_IOCompletionCallback", StringComparison.OrdinalIgnoreCase) == -1) - { - Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(exception)); - } - } - } - - public static void Shutdown() - { - ApplicationTaskCompletionSource.SetResult(true); - } - - public static void Restart() - { - _restartOnShutdown = true; - - Shutdown(); - } - - private static void StartNewInstance(StartupOptions startupOptions) - { - _logger.Info("Starting new instance"); - - string module = startupOptions.GetOption("-restartpath"); - string commandLineArgsString = startupOptions.GetOption("-restartargs") ?? string.Empty; - - if (string.IsNullOrWhiteSpace(module)) - { - module = Environment.GetCommandLineArgs().First(); - } - if (!startupOptions.ContainsOption("-restartargs")) - { - var args = Environment.GetCommandLineArgs() - .Skip(1) - .Select(NormalizeCommandLineArgument) - .ToArray(); - - commandLineArgsString = string.Join(" ", args); - } - - _logger.Info("Executable: {0}", module); - _logger.Info("Arguments: {0}", commandLineArgsString); - - Process.Start(module, commandLineArgsString); - } - - private static string NormalizeCommandLineArgument(string arg) - { - if (arg.IndexOf(" ", StringComparison.OrdinalIgnoreCase) == -1) - { - return arg; - } - - return "\"" + arg + "\""; - } - } - - // class NoCheckCertificatePolicy : ICertificatePolicy - // { - // public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) - // { - // return true; - // } - // } - - public class MonoEnvironmentInfo : EnvironmentInfo - { - - //public override string GetUserId() - //{ - // return Syscall.getuid().ToString(CultureInfo.InvariantCulture); - //} - } -} diff --git a/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs b/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs deleted file mode 100644 index eda3bcf97..000000000 --- a/MediaBrowser.Server.Mono/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Reflection; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. -[assembly: AssemblyTitle ("MediaBrowser.Server.Mono")] -[assembly: AssemblyDescription ("")] -[assembly: AssemblyConfiguration ("")] -[assembly: AssemblyCompany ("")] -[assembly: AssemblyProduct ("")] -[assembly: AssemblyCopyright ("Emby")] -[assembly: AssemblyTrademark ("")] -[assembly: AssemblyCulture ("")] -// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". -// The form "{Major}.{Minor}.*" will automatically update the build and revision, -// and "{Major}.{Minor}.{Build}.*" will update just the revision.
\ No newline at end of file diff --git a/MediaBrowser.Server.Mono/Properties/launchSettings.json b/MediaBrowser.Server.Mono/Properties/launchSettings.json deleted file mode 100644 index 058ad7adc..000000000 --- a/MediaBrowser.Server.Mono/Properties/launchSettings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "profiles": { - "EmbyServer": { - "commandName": "Project" - } - } -} diff --git a/MediaBrowser.Server.Mono/SocketSharp/HttpFile.cs b/MediaBrowser.Server.Mono/SocketSharp/HttpFile.cs deleted file mode 100644 index 1e7c93deb..000000000 --- a/MediaBrowser.Server.Mono/SocketSharp/HttpFile.cs +++ /dev/null @@ -1,14 +0,0 @@ -using MediaBrowser.Model.Services; -using System.IO; - -namespace EmbyServer.SocketSharp -{ - public class HttpFile : IHttpFile - { - public string Name { get; set; } - public string FileName { get; set; } - public long ContentLength { get; set; } - public string ContentType { get; set; } - public Stream InputStream { get; set; } - } -} diff --git a/MediaBrowser.Server.Mono/SocketSharp/RequestMono.cs b/MediaBrowser.Server.Mono/SocketSharp/RequestMono.cs deleted file mode 100644 index 9d2354316..000000000 --- a/MediaBrowser.Server.Mono/SocketSharp/RequestMono.cs +++ /dev/null @@ -1,807 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Globalization; -using System.IO; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using MediaBrowser.Model.Services; - -namespace EmbyServer.SocketSharp -{ - public partial class WebSocketSharpRequest : IHttpRequest - { - static internal string GetParameter(string header, string attr) - { - int ap = header.IndexOf(attr); - if (ap == -1) - return null; - - ap += attr.Length; - if (ap >= header.Length) - return null; - - char ending = header[ap]; - if (ending != '"') - ending = ' '; - - int end = header.IndexOf(ending, ap + 1); - if (end == -1) - return ending == '"' ? null : header.Substring(ap); - - return header.Substring(ap + 1, end - ap - 1); - } - - async Task LoadMultiPart(WebROCollection form) - { - string boundary = GetParameter(ContentType, "; boundary="); - if (boundary == null) - return; - - using (var requestStream = InputStream) - { - //DB: 30/01/11 - Hack to get around non-seekable stream and received HTTP request - //Not ending with \r\n? - var ms = new MemoryStream(32 * 1024); - await requestStream.CopyToAsync(ms).ConfigureAwait(false); - - var input = ms; - ms.WriteByte((byte)'\r'); - ms.WriteByte((byte)'\n'); - - input.Position = 0; - - //Uncomment to debug - //var content = new StreamReader(ms).ReadToEnd(); - //Console.WriteLine(boundary + "::" + content); - //input.Position = 0; - - var multi_part = new HttpMultipart(input, boundary, ContentEncoding); - - HttpMultipart.Element e; - while ((e = multi_part.ReadNextElement()) != null) - { - if (e.Filename == null) - { - byte[] copy = new byte[e.Length]; - - input.Position = e.Start; - input.Read(copy, 0, (int)e.Length); - - form.Add(e.Name, (e.Encoding ?? ContentEncoding).GetString(copy, 0, copy.Length)); - } - else - { - // - // We use a substream, as in 2.x we will support large uploads streamed to disk, - // - HttpPostedFile sub = new HttpPostedFile(e.Filename, e.ContentType, input, e.Start, e.Length); - files[e.Name] = sub; - } - } - } - } - - public async Task<QueryParamCollection> GetFormData() - { - var form = new WebROCollection(); - files = new Dictionary<string, HttpPostedFile>(); - - if (IsContentType("multipart/form-data", true)) - { - await LoadMultiPart(form).ConfigureAwait(false); - } - else if (IsContentType("application/x-www-form-urlencoded", true)) - { - await LoadWwwForm(form).ConfigureAwait(false); - } - -#if NET_4_0 - if (validateRequestNewMode && !checked_form) { - // Setting this before calling the validator prevents - // possible endless recursion - checked_form = true; - ValidateNameValueCollection ("Form", query_string_nvc, RequestValidationSource.Form); - } else -#endif - if (validate_form && !checked_form) - { - checked_form = true; - ValidateNameValueCollection("Form", form); - } - - return form; - } - - public string Accept - { - get - { - return string.IsNullOrEmpty(request.Headers["Accept"]) ? null : request.Headers["Accept"]; - } - } - - public string Authorization - { - get - { - return 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; - - static void ThrowValidationException(string name, string key, string value) - { - string v = "\"" + value + "\""; - if (v.Length > 20) - 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); - - throw new Exception(msg); - } - - static void ValidateNameValueCollection(string name, QueryParamCollection coll) - { - if (coll == null) - return; - - foreach (var pair in coll) - { - var key = pair.Name; - var val = pair.Value; - if (val != null && val.Length > 0 && IsInvalidString(val)) - ThrowValidationException(name, key, val); - } - } - - internal static bool IsInvalidString(string val) - { - int validationFailureIndex; - - return IsInvalidString(val, out validationFailureIndex); - } - - internal static bool IsInvalidString(string val, out int validationFailureIndex) - { - validationFailureIndex = 0; - - int len = val.Length; - if (len < 2) - return false; - - char current = val[0]; - for (int idx = 1; idx < len; idx++) - { - char next = val[idx]; - // See http://secunia.com/advisories/14325 - if (current == '<' || current == '\xff1c') - { - if (next == '!' || next < ' ' - || (next >= 'a' && next <= 'z') - || (next >= 'A' && next <= 'Z')) - { - validationFailureIndex = idx - 1; - return true; - } - } - else if (current == '&' && next == '#') - { - validationFailureIndex = idx - 1; - return true; - } - - current = next; - } - - return false; - } - - public void ValidateInput() - { - validate_cookies = true; - validate_query_string = true; - validate_form = true; - } - - bool IsContentType(string ct, bool starts_with) - { - if (ct == null || ContentType == null) return false; - - if (starts_with) - return StrUtils.StartsWith(ContentType, ct, true); - - return string.Equals(ContentType, ct, StringComparison.OrdinalIgnoreCase); - } - - async Task LoadWwwForm(WebROCollection form) - { - using (Stream input = InputStream) - { - using (var ms = new MemoryStream()) - { - await input.CopyToAsync(ms).ConfigureAwait(false); - ms.Position = 0; - - using (StreamReader s = new StreamReader(ms, ContentEncoding)) - { - StringBuilder key = new StringBuilder(); - StringBuilder value = new StringBuilder(); - int c; - - while ((c = s.Read()) != -1) - { - if (c == '=') - { - value.Length = 0; - while ((c = s.Read()) != -1) - { - if (c == '&') - { - AddRawKeyValue(form, key, value); - break; - } - else - value.Append((char)c); - } - if (c == -1) - { - AddRawKeyValue(form, key, value); - return; - } - } - else if (c == '&') - AddRawKeyValue(form, key, value); - else - key.Append((char)c); - } - if (c == -1) - AddRawKeyValue(form, key, value); - } - } - } - } - - void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value) - { - string decodedKey = WebUtility.UrlDecode(key.ToString()); - form.Add(decodedKey, - WebUtility.UrlDecode(value.ToString())); - - key.Length = 0; - value.Length = 0; - } - - Dictionary<string, HttpPostedFile> files; - - class WebROCollection : QueryParamCollection - { - public override string ToString() - { - StringBuilder result = new StringBuilder(); - foreach (var pair in this) - { - if (result.Length > 0) - result.Append('&'); - - var key = pair.Name; - if (key != null && key.Length > 0) - { - result.Append(key); - result.Append('='); - } - result.Append(pair.Value); - } - - return result.ToString(); - } - } - - public sealed class HttpPostedFile - { - string name; - string content_type; - Stream stream; - - class ReadSubStream : Stream - { - Stream s; - long offset; - long end; - long position; - - public ReadSubStream(Stream s, long offset, long length) - { - this.s = s; - this.offset = offset; - this.end = offset + length; - position = offset; - } - - public override void Flush() - { - } - - public override int Read(byte[] buffer, int dest_offset, int count) - { - if (buffer == null) - throw new ArgumentNullException("buffer"); - - if (dest_offset < 0) - throw new ArgumentOutOfRangeException("dest_offset", "< 0"); - - if (count < 0) - throw new ArgumentOutOfRangeException("count", "< 0"); - - int len = buffer.Length; - if (dest_offset > len) - throw new ArgumentException("destination offset is beyond array size"); - // reordered to avoid possible integer overflow - if (dest_offset > len - count) - throw new ArgumentException("Reading would overrun buffer"); - - if (count > end - position) - count = (int)(end - position); - - if (count <= 0) - return 0; - - s.Position = position; - int result = s.Read(buffer, dest_offset, count); - if (result > 0) - position += result; - else - position = end; - - return result; - } - - public override int ReadByte() - { - if (position >= end) - return -1; - - s.Position = position; - int result = s.ReadByte(); - if (result < 0) - position = end; - else - position++; - - return result; - } - - public override long Seek(long d, SeekOrigin origin) - { - long real; - switch (origin) - { - case SeekOrigin.Begin: - real = offset + d; - break; - case SeekOrigin.End: - real = end + d; - break; - case SeekOrigin.Current: - real = position + d; - break; - default: - throw new ArgumentException(); - } - - long virt = real - offset; - if (virt < 0 || virt > Length) - throw new ArgumentException(); - - position = s.Seek(real, SeekOrigin.Begin); - return position; - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - public override bool CanRead - { - get { return true; } - } - public override bool CanSeek - { - get { return true; } - } - public override bool CanWrite - { - get { return false; } - } - - public override long Length - { - get { return end - offset; } - } - - public override long Position - { - get - { - return position - offset; - } - set - { - if (value > Length) - throw new ArgumentOutOfRangeException(); - - position = Seek(value, SeekOrigin.Begin); - } - } - } - - internal HttpPostedFile(string name, string content_type, Stream base_stream, long offset, long length) - { - this.name = name; - this.content_type = content_type; - this.stream = new ReadSubStream(base_stream, offset, length); - } - - public string ContentType - { - get - { - return content_type; - } - } - - public int ContentLength - { - get - { - return (int)stream.Length; - } - } - - public string FileName - { - get - { - return name; - } - } - - public Stream InputStream - { - get - { - return stream; - } - } - } - - class Helpers - { - public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture; - } - - internal sealed class StrUtils - { - public static bool StartsWith(string str1, string str2, bool ignore_case) - { - if (string.IsNullOrEmpty(str1)) - { - return false; - } - - var comparison = ignore_case ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - return str1.IndexOf(str2, comparison) == 0; - } - - public static bool EndsWith(string str1, string str2, bool ignore_case) - { - int l2 = str2.Length; - if (l2 == 0) - return true; - - int l1 = str1.Length; - if (l2 > l1) - return false; - - var comparison = ignore_case ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - return str1.IndexOf(str2, comparison) == str1.Length - str2.Length - 1; - } - } - - class HttpMultipart - { - - public class Element - { - public string ContentType; - public string Name; - public string Filename; - public Encoding Encoding; - public long Start; - public long Length; - - public override string ToString() - { - return "ContentType " + ContentType + ", Name " + Name + ", Filename " + Filename + ", Start " + - Start.ToString() + ", Length " + Length.ToString(); - } - } - - Stream data; - string boundary; - byte[] boundary_bytes; - byte[] buffer; - bool at_eof; - Encoding encoding; - StringBuilder sb; - - const byte HYPHEN = (byte)'-', LF = (byte)'\n', CR = (byte)'\r'; - - // See RFC 2046 - // In the case of multipart entities, in which one or more different - // sets of data are combined in a single body, a "multipart" media type - // field must appear in the entity's header. The body must then contain - // one or more body parts, each preceded by a boundary delimiter line, - // and the last one followed by a closing boundary delimiter line. - // After its boundary delimiter line, each body part then consists of a - // header area, a blank line, and a body area. Thus a body part is - // similar to an RFC 822 message in syntax, but different in meaning. - - 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 '--' - this.encoding = encoding; - sb = new StringBuilder(); - } - - string ReadLine() - { - // CRLF or LF are ok as line endings. - bool got_cr = false; - int b = 0; - sb.Length = 0; - while (true) - { - b = data.ReadByte(); - if (b == -1) - { - return null; - } - - if (b == LF) - { - break; - } - got_cr = b == CR; - sb.Append((char)b); - } - - if (got_cr) - sb.Length--; - - return sb.ToString(); - - } - - static string GetContentDispositionAttribute(string l, string name) - { - int idx = l.IndexOf(name + "=\""); - if (idx < 0) - return null; - int begin = idx + name.Length + "=\"".Length; - int end = l.IndexOf('"', begin); - if (end < 0) - return null; - if (begin == end) - return ""; - return l.Substring(begin, end - begin); - } - - string GetContentDispositionAttributeWithEncoding(string l, string name) - { - int idx = l.IndexOf(name + "=\""); - if (idx < 0) - return null; - int begin = idx + name.Length + "=\"".Length; - int end = l.IndexOf('"', begin); - if (end < 0) - return null; - if (begin == end) - return ""; - - string temp = l.Substring(begin, end - begin); - byte[] source = new byte[temp.Length]; - for (int i = temp.Length - 1; i >= 0; i--) - source[i] = (byte)temp[i]; - - return encoding.GetString(source, 0, source.Length); - } - - bool ReadBoundary() - { - try - { - string line = ReadLine(); - while (line == "") - line = ReadLine(); - if (line[0] != '-' || line[1] != '-') - return false; - - if (!StrUtils.EndsWith(line, boundary, false)) - return true; - } - catch - { - } - - return false; - } - - string ReadHeaders() - { - string s = ReadLine(); - if (s == "") - return null; - - return s; - } - - bool CompareBytes(byte[] orig, byte[] other) - { - for (int i = orig.Length - 1; i >= 0; i--) - if (orig[i] != other[i]) - return false; - - return true; - } - - long MoveToNextBoundary() - { - long retval = 0; - bool got_cr = false; - - int state = 0; - int c = data.ReadByte(); - while (true) - { - if (c == -1) - return -1; - - if (state == 0 && c == LF) - { - retval = data.Position - 1; - if (got_cr) - retval--; - state = 1; - c = data.ReadByte(); - } - else if (state == 0) - { - got_cr = c == CR; - c = data.ReadByte(); - } - else if (state == 1 && c == '-') - { - c = data.ReadByte(); - if (c == -1) - return -1; - - if (c != '-') - { - state = 0; - got_cr = false; - continue; // no ReadByte() here - } - - int nread = data.Read(buffer, 0, buffer.Length); - int bl = buffer.Length; - if (nread != bl) - return -1; - - if (!CompareBytes(boundary_bytes, buffer)) - { - state = 0; - data.Position = retval + 2; - if (got_cr) - { - data.Position++; - got_cr = false; - } - c = data.ReadByte(); - continue; - } - - if (buffer[bl - 2] == '-' && buffer[bl - 1] == '-') - { - at_eof = true; - } - else if (buffer[bl - 2] != CR || buffer[bl - 1] != LF) - { - state = 0; - data.Position = retval + 2; - if (got_cr) - { - data.Position++; - got_cr = false; - } - c = data.ReadByte(); - continue; - } - data.Position = retval + 2; - if (got_cr) - data.Position++; - break; - } - else - { - // state == 1 - state = 0; // no ReadByte() here - } - } - - return retval; - } - - public Element ReadNextElement() - { - if (at_eof || ReadBoundary()) - return null; - - Element 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; - } - - static string StripPath(string path) - { - if (path == null || path.Length == 0) - return path; - - if (path.IndexOf(":\\") != 1 && !path.StartsWith("\\\\")) - return path; - return path.Substring(path.LastIndexOf('\\') + 1); - } - } - - } -} diff --git a/MediaBrowser.Server.Mono/SocketSharp/SharpWebSocket.cs b/MediaBrowser.Server.Mono/SocketSharp/SharpWebSocket.cs deleted file mode 100644 index 6c2dd0f76..000000000 --- a/MediaBrowser.Server.Mono/SocketSharp/SharpWebSocket.cs +++ /dev/null @@ -1,159 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Net.WebSockets; -using Emby.Server.Implementations.Net; - -namespace EmbyServer.SocketSharp -{ - public class SharpWebSocket : IWebSocket - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - public event EventHandler<EventArgs> Closed; - - /// <summary> - /// Gets or sets the web socket. - /// </summary> - /// <value>The web socket.</value> - private SocketHttpListener.WebSocket WebSocket { get; set; } - - private TaskCompletionSource<bool> _taskCompletionSource = new TaskCompletionSource<bool>(); - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger) - { - if (socket == null) - { - throw new ArgumentNullException("socket"); - } - - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - _logger = logger; - WebSocket = socket; - - socket.OnMessage += socket_OnMessage; - socket.OnClose += socket_OnClose; - socket.OnError += socket_OnError; - - WebSocket.ConnectAsServer(); - } - - public Task StartReceive() - { - return _taskCompletionSource.Task; - } - - void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e) - { - _logger.Error("Error in SharpWebSocket: {0}", e.Message ?? string.Empty); - //EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); - } - - void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e) - { - _taskCompletionSource.TrySetResult(true); - - EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger); - } - - 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); - } - } - - /// <summary> - /// Gets or sets the state. - /// </summary> - /// <value>The state.</value> - public WebSocketState State - { - get - { - return WebSocket.ReadyState; - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) - { - return WebSocket.SendAsync(bytes); - } - - /// <summary> - /// Sends the asynchronous. - /// </summary> - /// <param name="text">The text.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) - { - return WebSocket.SendAsync(text); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <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) - { - if (dispose) - { - WebSocket.OnMessage -= socket_OnMessage; - WebSocket.OnClose -= socket_OnClose; - WebSocket.OnError -= socket_OnError; - - _cancellationTokenSource.Cancel(); - - WebSocket.Close(); - } - } - - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> - 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; } - } -} diff --git a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs deleted file mode 100644 index e75a38e38..000000000 --- a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpListener.cs +++ /dev/null @@ -1,262 +0,0 @@ -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using SocketHttpListener.Net; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Cryptography; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; -using MediaBrowser.Model.Text; -using Emby.Server.Implementations.Net; -using Emby.Server.Implementations.HttpServer; - -namespace EmbyServer.SocketSharp -{ - public class WebSocketSharpListener : IHttpListener - { - private HttpListener _listener; - - private readonly ILogger _logger; - private readonly X509Certificate _certificate; - private readonly IStreamHelper _streamHelper; - private readonly ITextEncoding _textEncoding; - private readonly INetworkManager _networkManager; - private readonly ISocketFactory _socketFactory; - private readonly ICryptoProvider _cryptoProvider; - private readonly IFileSystem _fileSystem; - private readonly bool _enableDualMode; - private readonly IEnvironmentInfo _environment; - - private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource(); - private CancellationToken _disposeCancellationToken; - - public WebSocketSharpListener(ILogger logger, X509Certificate certificate, IStreamHelper streamHelper, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, bool enableDualMode, IFileSystem fileSystem, IEnvironmentInfo environment) - { - _logger = logger; - _certificate = certificate; - _streamHelper = streamHelper; - _textEncoding = textEncoding; - _networkManager = networkManager; - _socketFactory = socketFactory; - _cryptoProvider = cryptoProvider; - _enableDualMode = enableDualMode; - _fileSystem = fileSystem; - _environment = environment; - - _disposeCancellationToken = _disposeCancellationTokenSource.Token; - } - - public Func<Exception, IRequest, bool, bool, Task> ErrorHandler { get; set; } - public Func<IHttpRequest, string, string, string, CancellationToken, Task> RequestHandler { get; set; } - - public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; } - - public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; } - - public void Start(IEnumerable<string> urlPrefixes) - { - if (_listener == null) - _listener = new HttpListener(_logger, _cryptoProvider, _socketFactory, _networkManager, _textEncoding, _streamHelper, _fileSystem, _environment); - - _listener.EnableDualMode = _enableDualMode; - - if (_certificate != null) - { - _listener.LoadCert(_certificate); - } - - foreach (var prefix in urlPrefixes) - { - _logger.Info("Adding HttpListener prefix " + prefix); - _listener.Prefixes.Add(prefix); - } - - _listener.OnContext = ProcessContext; - - _listener.Start(); - } - - private void ProcessContext(HttpListenerContext context) - { - //InitTask(context, _disposeCancellationToken); - Task.Run(() => InitTask(context, _disposeCancellationToken)); - } - - private void LogRequest(ILogger logger, HttpListenerRequest request) - { - var url = request.Url.ToString(); - - logger.Info("{0} {1}. UserAgent: {2}", request.IsWebSocketRequest ? "WS" : "HTTP " + request.HttpMethod, url, request.UserAgent ?? string.Empty); - } - - private Task InitTask(HttpListenerContext context, CancellationToken cancellationToken) - { - IHttpRequest httpReq = null; - var request = context.Request; - - try - { - if (request.IsWebSocketRequest) - { - LogRequest(_logger, request); - - return ProcessWebSocketRequest(context); - } - - httpReq = GetRequest(context); - } - catch (Exception ex) - { - _logger.ErrorException("Error processing request", ex); - - httpReq = httpReq ?? GetRequest(context); - return ErrorHandler(ex, httpReq, true, true); - } - - var uri = request.Url; - - return RequestHandler(httpReq, uri.OriginalString, uri.Host, uri.LocalPath, cancellationToken); - } - - private async Task ProcessWebSocketRequest(HttpListenerContext ctx) - { - try - { - var endpoint = ctx.Request.RemoteEndPoint.ToString(); - var url = ctx.Request.RawUrl; - - var queryString = ctx.Request.QueryString; - - var connectingArgs = new WebSocketConnectingEventArgs - { - Url = url, - QueryString = queryString, - Endpoint = endpoint - }; - - if (WebSocketConnecting != null) - { - WebSocketConnecting(connectingArgs); - } - - if (connectingArgs.AllowConnection) - { - _logger.Debug("Web socket connection allowed"); - - var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); - - if (WebSocketConnected != null) - { - var socket = new SharpWebSocket(webSocketContext.WebSocket, _logger); - - WebSocketConnected(new WebSocketConnectEventArgs - { - Url = url, - QueryString = queryString, - WebSocket = socket, - Endpoint = endpoint - }); - - await ReceiveWebSocket(ctx, socket).ConfigureAwait(false); - } - } - else - { - _logger.Warn("Web socket connection not allowed"); - ctx.Response.StatusCode = 401; - ctx.Response.Close(); - } - } - catch (Exception ex) - { - _logger.ErrorException("AcceptWebSocketAsync error", ex); - ctx.Response.StatusCode = 500; - ctx.Response.Close(); - } - } - - private async Task ReceiveWebSocket(HttpListenerContext ctx, SharpWebSocket socket) - { - try - { - await socket.StartReceive().ConfigureAwait(false); - } - finally - { - TryClose(ctx, 200); - } - } - - private void TryClose(HttpListenerContext ctx, int statusCode) - { - try - { - ctx.Response.StatusCode = 200; - ctx.Response.Close(); - } - catch (ObjectDisposedException) - { - } - catch (Exception ex) - { - _logger.ErrorException("Error closing web socket response", ex); - } - } - - private IHttpRequest GetRequest(HttpListenerContext httpContext) - { - var urlSegments = httpContext.Request.Url.Segments; - - var operationName = urlSegments[urlSegments.Length - 1]; - - var req = new WebSocketSharpRequest(httpContext, operationName, _logger); - - return req; - } - - public Task Stop() - { - _disposeCancellationTokenSource.Cancel(); - - if (_listener != null) - { - _listener.Close(); - } - - return Task.CompletedTask; - } - - public void Dispose() - { - Dispose(true); - } - - private bool _disposed; - private readonly object _disposeLock = new object(); - protected virtual void Dispose(bool disposing) - { - if (_disposed) return; - - lock (_disposeLock) - { - if (_disposed) return; - - if (disposing) - { - Stop(); - } - - //release unmanaged resources here... - _disposed = true; - } - } - } - -}
\ No newline at end of file diff --git a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpRequest.cs deleted file mode 100644 index 84e37a58c..000000000 --- a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpRequest.cs +++ /dev/null @@ -1,556 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Emby.Server.Implementations.HttpServer; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Services; -using SocketHttpListener.Net; -using IHttpFile = MediaBrowser.Model.Services.IHttpFile; -using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest; -using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; -using IResponse = MediaBrowser.Model.Services.IResponse; -using System.Threading.Tasks; - -namespace EmbyServer.SocketSharp -{ - public partial class WebSocketSharpRequest : IHttpRequest - { - private readonly HttpListenerRequest request; - private readonly IHttpResponse response; - - public WebSocketSharpRequest(HttpListenerContext httpContext, string operationName, ILogger logger) - { - this.OperationName = operationName; - this.request = httpContext.Request; - this.response = new WebSocketSharpResponse(logger, httpContext.Response, this); - - //HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]); - } - - private static string GetHandlerPathIfAny(string listenerUrl) - { - if (listenerUrl == null) return null; - var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase); - if (pos == -1) return null; - var startHostUrl = listenerUrl.Substring(pos + "://".Length); - var endPos = startHostUrl.IndexOf('/'); - if (endPos == -1) return null; - var endHostUrl = startHostUrl.Substring(endPos + 1); - return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/'); - } - - public HttpListenerRequest HttpRequest - { - get { return request; } - } - - public object OriginalRequest - { - get { return request; } - } - - public IResponse Response - { - get { return response; } - } - - public IHttpResponse HttpResponse - { - get { return response; } - } - - public string OperationName { get; set; } - - public object Dto { get; set; } - - public string RawUrl - { - get { return request.RawUrl; } - } - - public string AbsoluteUri - { - get { return request.Url.AbsoluteUri.TrimEnd('/'); } - } - - public string UserHostAddress - { - get { return request.UserHostAddress; } - } - - public string XForwardedFor - { - get - { - return String.IsNullOrEmpty(request.Headers["X-Forwarded-For"]) ? null : request.Headers["X-Forwarded-For"]; - } - } - - public int? XForwardedPort - { - get - { - return string.IsNullOrEmpty(request.Headers["X-Forwarded-Port"]) ? (int?)null : int.Parse(request.Headers["X-Forwarded-Port"]); - } - } - - public string XForwardedProtocol - { - get - { - return string.IsNullOrEmpty(request.Headers["X-Forwarded-Proto"]) ? null : request.Headers["X-Forwarded-Proto"]; - } - } - - public string XRealIp - { - get - { - return String.IsNullOrEmpty(request.Headers["X-Real-IP"]) ? null : request.Headers["X-Real-IP"]; - } - } - - private string remoteIp; - public string RemoteIp - { - get - { - return remoteIp ?? - (remoteIp = (CheckBadChars(XForwardedFor)) ?? - (NormalizeIp(CheckBadChars(XRealIp)) ?? - (request.RemoteEndPoint != null ? NormalizeIp(request.RemoteEndPoint.Address.ToString()) : null))); - } - } - - private static readonly char[] HttpTrimCharacters = new char[] { (char)0x09, (char)0xA, (char)0xB, (char)0xC, (char)0xD, (char)0x20 }; - - // - // CheckBadChars - throws on invalid chars to be not found in header name/value - // - internal static string CheckBadChars(string name) - { - if (name == null || name.Length == 0) - { - return name; - } - - // VALUE check - //Trim spaces from both ends - name = name.Trim(HttpTrimCharacters); - - //First, check for correctly formed multi-line value - //Second, check for absenece of CTL characters - int crlf = 0; - for (int i = 0; i < name.Length; ++i) - { - char c = (char)(0x000000ff & (uint)name[i]); - switch (crlf) - { - case 0: - if (c == '\r') - { - crlf = 1; - } - else if (c == '\n') - { - // Technically this is bad HTTP. But it would be a breaking change to throw here. - // Is there an exploit? - crlf = 2; - } - else if (c == 127 || (c < ' ' && c != '\t')) - { - 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"); - } - } - if (crlf != 0) - { - throw new ArgumentException("net_WebHeaderInvalidCRLFChars"); - } - return name; - } - - internal static bool ContainsNonAsciiChars(string token) - { - for (int i = 0; i < token.Length; ++i) - { - if ((token[i] < 0x20) || (token[i] > 0x7e)) - { - return true; - } - } - return false; - } - - private string NormalizeIp(string ip) - { - if (!string.IsNullOrWhiteSpace(ip)) - { - // Handle ipv4 mapped to ipv6 - const string srch = "::ffff:"; - var index = ip.IndexOf(srch, StringComparison.OrdinalIgnoreCase); - if (index == 0) - { - ip = ip.Substring(srch.Length); - } - } - - return ip; - } - - public bool IsSecureConnection - { - get { return request.IsSecureConnection || XForwardedProtocol == "https"; } - } - - public string[] AcceptTypes - { - get { return request.AcceptTypes; } - } - - private Dictionary<string, object> items; - public Dictionary<string, object> Items - { - get { return items ?? (items = new Dictionary<string, object>()); } - } - - private string responseContentType; - public string ResponseContentType - { - get - { - return responseContentType - ?? (responseContentType = GetResponseContentType(this)); - } - set - { - this.responseContentType = value; - } - } - - public const string FormUrlEncoded = "application/x-www-form-urlencoded"; - public const string MultiPartFormData = "multipart/form-data"; - public static string GetResponseContentType(IRequest httpReq) - { - var specifiedContentType = GetQueryStringContentType(httpReq); - if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType; - - var serverDefaultContentType = "application/json"; - - var acceptContentTypes = httpReq.AcceptTypes; - string defaultContentType = null; - if (HasAnyOfContentTypes(httpReq, FormUrlEncoded, MultiPartFormData)) - { - defaultContentType = serverDefaultContentType; - } - - var acceptsAnything = false; - var hasDefaultContentType = !string.IsNullOrEmpty(defaultContentType); - if (acceptContentTypes != null) - { - foreach (var acceptsType in acceptContentTypes) - { - var contentType = HttpResultFactory.GetRealContentType(acceptsType); - acceptsAnything = acceptsAnything || contentType == "*/*"; - } - - if (acceptsAnything) - { - if (hasDefaultContentType) - return defaultContentType; - if (serverDefaultContentType != null) - return serverDefaultContentType; - } - } - - if (acceptContentTypes == null && httpReq.ContentType == Soap11) - { - return Soap11; - } - - //We could also send a '406 Not Acceptable', but this is allowed also - return serverDefaultContentType; - } - - public const string Soap11 = "text/xml; charset=utf-8"; - - public static bool HasAnyOfContentTypes(IRequest request, params string[] contentTypes) - { - if (contentTypes == null || request.ContentType == null) return false; - foreach (var contentType in contentTypes) - { - if (IsContentType(request, contentType)) return true; - } - return false; - } - - public static bool IsContentType(IRequest request, string contentType) - { - return request.ContentType.StartsWith(contentType, StringComparison.OrdinalIgnoreCase); - } - - public const string Xml = "application/xml"; - private static string GetQueryStringContentType(IRequest httpReq) - { - var format = httpReq.QueryString["format"]; - if (format == null) - { - const int formatMaxLength = 4; - var pi = httpReq.PathInfo; - if (pi == null || pi.Length <= formatMaxLength) return null; - if (pi[0] == '/') pi = pi.Substring(1); - format = LeftPart(pi, '/'); - if (format.Length > formatMaxLength) return null; - } - - format = LeftPart(format, '.').ToLower(); - if (format.Contains("json")) return "application/json"; - if (format.Contains("xml")) return Xml; - - return null; - } - - public static string LeftPart(string strVal, char needle) - { - if (strVal == null) return null; - var pos = strVal.IndexOf(needle); - return pos == -1 - ? strVal - : strVal.Substring(0, pos); - } - - public static string HandlerFactoryPath; - - private string pathInfo; - public string PathInfo - { - get - { - if (this.pathInfo == null) - { - var mode = HandlerFactoryPath; - - var pos = request.RawUrl.IndexOf("?"); - if (pos != -1) - { - var path = request.RawUrl.Substring(0, pos); - this.pathInfo = GetPathInfo( - path, - mode, - mode ?? ""); - } - else - { - this.pathInfo = request.RawUrl; - } - - this.pathInfo = System.Net.WebUtility.UrlDecode(pathInfo); - this.pathInfo = NormalizePathInfo(pathInfo, mode); - } - return this.pathInfo; - } - } - - private static string GetPathInfo(string fullPath, string mode, string appPath) - { - var pathInfo = ResolvePathInfoFromMappedPath(fullPath, mode); - if (!string.IsNullOrEmpty(pathInfo)) return pathInfo; - - //Wildcard mode relies on this to work out the handlerPath - pathInfo = ResolvePathInfoFromMappedPath(fullPath, appPath); - if (!string.IsNullOrEmpty(pathInfo)) return pathInfo; - - return fullPath; - } - - private static string ResolvePathInfoFromMappedPath(string fullPath, string mappedPathRoot) - { - if (mappedPathRoot == null) return null; - - var sbPathInfo = new StringBuilder(); - var fullPathParts = fullPath.Split('/'); - var mappedPathRootParts = mappedPathRoot.Split('/'); - var fullPathIndexOffset = mappedPathRootParts.Length - 1; - var pathRootFound = false; - - for (var fullPathIndex = 0; fullPathIndex < fullPathParts.Length; fullPathIndex++) - { - if (pathRootFound) - { - sbPathInfo.Append("/" + fullPathParts[fullPathIndex]); - } - else if (fullPathIndex - fullPathIndexOffset >= 0) - { - pathRootFound = true; - for (var mappedPathRootIndex = 0; mappedPathRootIndex < mappedPathRootParts.Length; mappedPathRootIndex++) - { - if (!string.Equals(fullPathParts[fullPathIndex - fullPathIndexOffset + mappedPathRootIndex], mappedPathRootParts[mappedPathRootIndex], StringComparison.OrdinalIgnoreCase)) - { - pathRootFound = false; - break; - } - } - } - } - if (!pathRootFound) return null; - - var path = sbPathInfo.ToString(); - return path.Length > 1 ? path.TrimEnd('/') : "/"; - } - - private Dictionary<string, System.Net.Cookie> cookies; - public IDictionary<string, System.Net.Cookie> Cookies - { - get - { - if (cookies == null) - { - cookies = new Dictionary<string, System.Net.Cookie>(); - foreach (var cookie in this.request.Cookies) - { - var httpCookie = (System.Net.Cookie) cookie; - cookies[httpCookie.Name] = new System.Net.Cookie(httpCookie.Name, httpCookie.Value, httpCookie.Path, httpCookie.Domain); - } - } - - return cookies; - } - } - - public string UserAgent - { - get { return request.UserAgent; } - } - - public QueryParamCollection Headers - { - get { return request.Headers; } - } - - private QueryParamCollection queryString; - public QueryParamCollection QueryString - { - get { return queryString ?? (queryString = MyHttpUtility.ParseQueryString(request.Url.Query)); } - } - - public bool IsLocal - { - get { return request.IsLocal; } - } - - private string httpMethod; - public string HttpMethod - { - get - { - return httpMethod - ?? (httpMethod = request.HttpMethod); - } - } - - public string Verb - { - get { return HttpMethod; } - } - - public string ContentType - { - get { return request.ContentType; } - } - - public Encoding contentEncoding; - public Encoding ContentEncoding - { - get { return contentEncoding ?? request.ContentEncoding; } - set { contentEncoding = value; } - } - - public Uri UrlReferrer - { - get { return request.UrlReferrer; } - } - - public static Encoding GetEncoding(string contentTypeHeader) - { - var param = GetParameter(contentTypeHeader, "charset="); - if (param == null) return null; - try - { - return Encoding.GetEncoding(param); - } - catch (ArgumentException) - { - return null; - } - } - - public Stream InputStream - { - get { return request.InputStream; } - } - - public long ContentLength - { - get { return request.ContentLength64; } - } - - private IHttpFile[] httpFiles; - public IHttpFile[] Files - { - get - { - if (httpFiles == null) - { - if (files == null) - return httpFiles = new IHttpFile[0]; - - httpFiles = new IHttpFile[files.Count]; - var i = 0; - foreach (var pair in files) - { - var reqFile = pair.Value; - httpFiles[i] = new HttpFile - { - ContentType = reqFile.ContentType, - ContentLength = reqFile.ContentLength, - FileName = reqFile.FileName, - InputStream = reqFile.InputStream, - }; - i++; - } - } - return httpFiles; - } - } - - public static string NormalizePathInfo(string pathInfo, string handlerPath) - { - if (handlerPath != null && pathInfo.TrimStart('/').StartsWith( - handlerPath, StringComparison.OrdinalIgnoreCase)) - { - return pathInfo.TrimStart('/').Substring(handlerPath.Length); - } - - return pathInfo; - } - } -} diff --git a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpResponse.cs b/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpResponse.cs deleted file mode 100644 index 15ff6675d..000000000 --- a/MediaBrowser.Server.Mono/SocketSharp/WebSocketSharpResponse.cs +++ /dev/null @@ -1,196 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Services; -using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse; -using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse; -using IRequest = MediaBrowser.Model.Services.IRequest; -using System.Net.Sockets; - -namespace EmbyServer.SocketSharp -{ - public class WebSocketSharpResponse : IHttpResponse - { - private readonly ILogger _logger; - private readonly HttpListenerResponse _response; - - public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request) - { - _logger = logger; - this._response = response; - Items = new Dictionary<string, object>(); - Request = request; - } - - public IRequest Request { get; private set; } - public Dictionary<string, object> Items { get; private set; } - public object OriginalResponse - { - get { return _response; } - } - - public int StatusCode - { - get { return this._response.StatusCode; } - set { this._response.StatusCode = value; } - } - - public string StatusDescription - { - get { return this._response.StatusDescription; } - set { this._response.StatusDescription = value; } - } - - public string ContentType - { - get { return _response.ContentType; } - set { _response.ContentType = value; } - } - - //public ICookies Cookies { get; set; } - - public void AddHeader(string name, string value) - { - if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase)) - { - ContentType = value; - return; - } - - _response.AddHeader(name, value); - } - - public QueryParamCollection Headers - { - get - { - return _response.Headers; - } - } - - public string GetHeader(string name) - { - return _response.Headers[name]; - } - - public void Redirect(string url) - { - _response.Redirect(url); - } - - public Stream OutputStream - { - get { return _response.OutputStream; } - } - - public void Close() - { - if (!this.IsClosed) - { - this.IsClosed = true; - - try - { - var response = this._response; - - var outputStream = response.OutputStream; - - // This is needed with compression - outputStream.Flush(); - outputStream.Dispose(); - - response.Close(); - } - catch (SocketException) - { - } - catch (Exception ex) - { - _logger.ErrorException("Error in HttpListenerResponseWrapper: " + ex.Message, ex); - } - } - } - - public bool IsClosed - { - get; - private set; - } - - 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 - _response.ContentLength64 = contentLength; - } - - public void SetCookie(Cookie cookie) - { - var cookieStr = AsHeaderValue(cookie); - _response.Headers.Add("Set-Cookie", cookieStr); - } - - public static string AsHeaderValue(Cookie cookie) - { - var defaultExpires = DateTime.MinValue; - - var path = cookie.Expires == defaultExpires - ? "/" - : cookie.Path ?? "/"; - - var sb = new StringBuilder(); - - sb.Append($"{cookie.Name}={cookie.Value};path={path}"); - - if (cookie.Expires != defaultExpires) - { - sb.Append($";expires={cookie.Expires:R}"); - } - - if (!string.IsNullOrEmpty(cookie.Domain)) - { - sb.Append($";domain={cookie.Domain}"); - } - //else if (restrictAllCookiesToDomain != null) - //{ - // sb.Append($";domain={restrictAllCookiesToDomain}"); - //} - - if (cookie.Secure) - { - sb.Append(";Secure"); - } - if (cookie.HttpOnly) - { - sb.Append(";HttpOnly"); - } - - return sb.ToString(); - } - - - public bool SendChunked - { - get { return _response.SendChunked; } - set { _response.SendChunked = value; } - } - - public bool KeepAlive { get; set; } - - public void ClearCookies() - { - } - - public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken) - { - return _response.TransmitFile(path, offset, count, fileShareMode, cancellationToken); - } - } -} |
