aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs4
-rw-r--r--Emby.Server.Implementations/Activity/ActivityRepository.cs4
-rw-r--r--Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs37
-rw-r--r--Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs92
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs116
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs17
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs3
-rw-r--r--Emby.Server.Implementations/ConfigurationOptions.cs4
-rw-r--r--Emby.Server.Implementations/Cryptography/CryptographyProvider.cs86
-rw-r--r--Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs3
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs19
-rw-r--r--Emby.Server.Implementations/Devices/DeviceId.cs4
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs4
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs17
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj2
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs16
-rw-r--r--Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs3
-rw-r--r--Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs6
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs174
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs154
-rw-r--r--Emby.Server.Implementations/HttpServer/ResponseFilter.cs26
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthService.cs48
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs3
-rw-r--r--Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs3
-rw-r--r--Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs69
-rw-r--r--Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs115
-rw-r--r--Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs257
-rw-r--r--Emby.Server.Implementations/Library/ExclusiveLiveStream.cs3
-rw-r--r--Emby.Server.Implementations/Library/InvalidAuthProvider.cs11
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs14
-rw-r--r--Emby.Server.Implementations/Library/LiveStreamHelper.cs2
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs6
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs27
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs2
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs49
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs9
-rw-r--r--Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs3
-rw-r--r--Emby.Server.Implementations/Library/Validators/PeopleValidator.cs4
-rw-r--r--Emby.Server.Implementations/Library/Validators/StudiosValidator.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs8
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs27
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs23
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs12
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs16
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs17
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs7
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs5
-rw-r--r--Emby.Server.Implementations/Localization/Core/da.json8
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/pl.json28
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt-BR.json14
-rw-r--r--Emby.Server.Implementations/Net/SocketFactory.cs14
-rw-r--r--Emby.Server.Implementations/Net/UdpSocket.cs31
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs167
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs94
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs2008
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs129
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt24
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs277
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs7
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs4
-rw-r--r--Emby.Server.Implementations/Security/AuthenticationRepository.cs6
-rw-r--r--Emby.Server.Implementations/Serialization/JsonSerializer.cs3
-rw-r--r--Emby.Server.Implementations/ServerApplicationPaths.cs27
-rw-r--r--Emby.Server.Implementations/Services/HttpResult.cs9
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs31
-rw-r--r--Emby.Server.Implementations/Services/ServiceController.cs4
-rw-r--r--Emby.Server.Implementations/Services/ServiceExec.cs2
-rw-r--r--Emby.Server.Implementations/Services/ServiceHandler.cs107
-rw-r--r--Emby.Server.Implementations/Session/HttpSessionController.cs2
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs16
-rw-r--r--Emby.Server.Implementations/SocketSharp/RequestMono.cs647
-rw-r--r--Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs198
-rw-r--r--Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs98
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs3
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs15
80 files changed, 1065 insertions, 4459 deletions
diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
index 0530a251c..3e44c9c0a 100644
--- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
+++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -75,7 +76,6 @@ namespace Emby.Server.Implementations.Activity
_sessionManager.AuthenticationFailed += OnAuthenticationFailed;
_sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded;
_sessionManager.SessionEnded += OnSessionEnded;
-
_sessionManager.PlaybackStart += OnPlaybackStart;
_sessionManager.PlaybackStopped += OnPlaybackStopped;
@@ -117,7 +117,7 @@ namespace Emby.Server.Implementations.Activity
{
Name = string.Format(_localization.GetLocalizedString("SubtitleDownloadFailureFromForItem"), e.Provider, Notifications.Notifications.GetItemName(e.Item)),
Type = "SubtitleDownloadFailure",
- ItemId = e.Item.Id.ToString("N"),
+ ItemId = e.Item.Id.ToString("N", CultureInfo.InvariantCulture),
ShortOverview = e.Exception.Message
});
}
diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs
index de46ab965..91371b833 100644
--- a/Emby.Server.Implementations/Activity/ActivityRepository.cs
+++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs
@@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Activity
}
else
{
- statement.TryBind("@UserId", entry.UserId.ToString("N"));
+ statement.TryBind("@UserId", entry.UserId.ToString("N", CultureInfo.InvariantCulture));
}
statement.TryBind("@DateCreated", entry.Date.ToDateTimeParamValue());
@@ -141,7 +141,7 @@ namespace Emby.Server.Implementations.Activity
}
else
{
- statement.TryBind("@UserId", entry.UserId.ToString("N"));
+ statement.TryBind("@UserId", entry.UserId.ToString("N", CultureInfo.InvariantCulture));
}
statement.TryBind("@DateCreated", entry.Date.ToDateTimeParamValue());
diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index 00cfa0c9a..f67a09daa 100644
--- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -10,6 +10,8 @@ namespace Emby.Server.Implementations.AppBase
/// </summary>
public abstract class BaseApplicationPaths : IApplicationPaths
{
+ private string _dataPath;
+
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
/// </summary>
@@ -30,27 +32,27 @@ namespace Emby.Server.Implementations.AppBase
}
/// <summary>
- /// Gets the path to the program data folder
+ /// Gets the path to the program data folder.
/// </summary>
/// <value>The program data path.</value>
- public string ProgramDataPath { get; private set; }
+ public string ProgramDataPath { get; }
/// <summary>
- /// Gets the path to the web UI resources folder
+ /// Gets the path to the web UI resources folder.
/// </summary>
/// <value>The web UI resources path.</value>
- public string WebPath { get; set; }
+ public string WebPath { get; }
/// <summary>
- /// Gets the path to the system folder
+ /// Gets the path to the system folder.
/// </summary>
+ /// <value>The path to the system folder.</value>
public string ProgramSystemPath { get; } = AppContext.BaseDirectory;
/// <summary>
- /// Gets the folder path to the data directory
+ /// Gets the folder path to the data directory.
/// </summary>
/// <value>The data directory.</value>
- private string _dataPath;
public string DataPath
{
get => _dataPath;
@@ -58,8 +60,9 @@ namespace Emby.Server.Implementations.AppBase
}
/// <summary>
- /// Gets the magic strings used for virtual path manipulation.
+ /// Gets the magic string used for virtual path manipulation.
/// </summary>
+ /// <value>The magic string used for virtual path manipulation.</value>
public string VirtualDataPath { get; } = "%AppDataPath%";
/// <summary>
@@ -69,43 +72,43 @@ namespace Emby.Server.Implementations.AppBase
public string ImageCachePath => Path.Combine(CachePath, "images");
/// <summary>
- /// Gets the path to the plugin directory
+ /// Gets the path to the plugin directory.
/// </summary>
/// <value>The plugins path.</value>
public string PluginsPath => Path.Combine(ProgramDataPath, "plugins");
/// <summary>
- /// Gets the path to the plugin configurations directory
+ /// Gets the path to the plugin configurations directory.
/// </summary>
/// <value>The plugin configurations path.</value>
public string PluginConfigurationsPath => Path.Combine(PluginsPath, "configurations");
/// <summary>
- /// Gets the path to the log directory
+ /// Gets the path to the log directory.
/// </summary>
/// <value>The log directory path.</value>
- public string LogDirectoryPath { get; private set; }
+ public string LogDirectoryPath { get; }
/// <summary>
- /// Gets the path to the application configuration root directory
+ /// Gets the path to the application configuration root directory.
/// </summary>
/// <value>The configuration directory path.</value>
- public string ConfigurationDirectoryPath { get; private set; }
+ public string ConfigurationDirectoryPath { get; }
/// <summary>
- /// Gets the path to the system configuration file
+ /// Gets the path to the system configuration file.
/// </summary>
/// <value>The system configuration file path.</value>
public string SystemConfigurationFilePath => Path.Combine(ConfigurationDirectoryPath, "system.xml");
/// <summary>
- /// Gets the folder path to the cache directory
+ /// Gets or sets the folder path to the cache directory.
/// </summary>
/// <value>The cache directory.</value>
public string CachePath { get; set; }
/// <summary>
- /// Gets the folder path to the temp directory within the cache folder
+ /// Gets the folder path to the temp directory within the cache folder.
/// </summary>
/// <value>The temp directory.</value>
public string TempDirectory => Path.Combine(CachePath, "temp");
diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index af60a8dce..4832c19c4 100644
--- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -19,11 +20,44 @@ namespace Emby.Server.Implementations.AppBase
/// </summary>
public abstract class BaseConfigurationManager : IConfigurationManager
{
+ private readonly IFileSystem _fileSystem;
+
+ private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
+
+ private ConfigurationStore[] _configurationStores = Array.Empty<ConfigurationStore>();
+ private IConfigurationFactory[] _configurationFactories = Array.Empty<IConfigurationFactory>();
+
/// <summary>
- /// Gets the type of the configuration.
+ /// The _configuration loaded.
/// </summary>
- /// <value>The type of the configuration.</value>
- protected abstract Type ConfigurationType { get; }
+ private bool _configurationLoaded;
+
+ /// <summary>
+ /// The _configuration sync lock.
+ /// </summary>
+ private object _configurationSyncLock = new object();
+
+ /// <summary>
+ /// The _configuration.
+ /// </summary>
+ private BaseApplicationConfiguration _configuration;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
+ /// </summary>
+ /// <param name="applicationPaths">The application paths.</param>
+ /// <param name="loggerFactory">The logger factory.</param>
+ /// <param name="xmlSerializer">The XML serializer.</param>
+ /// <param name="fileSystem">The file system</param>
+ protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
+ {
+ CommonApplicationPaths = applicationPaths;
+ XmlSerializer = xmlSerializer;
+ _fileSystem = fileSystem;
+ Logger = loggerFactory.CreateLogger(GetType().Name);
+
+ UpdateCachePath();
+ }
/// <summary>
/// Occurs when [configuration updated].
@@ -41,6 +75,12 @@ namespace Emby.Server.Implementations.AppBase
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
/// <summary>
+ /// Gets the type of the configuration.
+ /// </summary>
+ /// <value>The type of the configuration.</value>
+ protected abstract Type ConfigurationType { get; }
+
+ /// <summary>
/// Gets the logger.
/// </summary>
/// <value>The logger.</value>
@@ -56,21 +96,8 @@ namespace Emby.Server.Implementations.AppBase
/// </summary>
/// <value>The application paths.</value>
public IApplicationPaths CommonApplicationPaths { get; private set; }
- public readonly IFileSystem FileSystem;
/// <summary>
- /// The _configuration loaded
- /// </summary>
- private bool _configurationLoaded;
- /// <summary>
- /// The _configuration sync lock
- /// </summary>
- private object _configurationSyncLock = new object();
- /// <summary>
- /// The _configuration
- /// </summary>
- private BaseApplicationConfiguration _configuration;
- /// <summary>
/// Gets the system configuration
/// </summary>
/// <value>The configuration.</value>
@@ -90,26 +117,6 @@ namespace Emby.Server.Implementations.AppBase
}
}
- private ConfigurationStore[] _configurationStores = { };
- private IConfigurationFactory[] _configurationFactories = { };
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
- /// </summary>
- /// <param name="applicationPaths">The application paths.</param>
- /// <param name="loggerFactory">The logger factory.</param>
- /// <param name="xmlSerializer">The XML serializer.</param>
- /// <param name="fileSystem">The file system</param>
- protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IXmlSerializer xmlSerializer, IFileSystem fileSystem)
- {
- CommonApplicationPaths = applicationPaths;
- XmlSerializer = xmlSerializer;
- FileSystem = fileSystem;
- Logger = loggerFactory.CreateLogger(GetType().Name);
-
- UpdateCachePath();
- }
-
public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
{
_configurationFactories = factories.ToArray();
@@ -171,6 +178,7 @@ namespace Emby.Server.Implementations.AppBase
private void UpdateCachePath()
{
string cachePath;
+
// If the configuration file has no entry (i.e. not set in UI)
if (string.IsNullOrWhiteSpace(CommonConfiguration.CachePath))
{
@@ -207,12 +215,16 @@ namespace Emby.Server.Implementations.AppBase
var newPath = newConfig.CachePath;
if (!string.IsNullOrWhiteSpace(newPath)
- && !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath))
+ && !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath, StringComparison.Ordinal))
{
// Validate
if (!Directory.Exists(newPath))
{
- throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
+ throw new FileNotFoundException(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} does not exist.",
+ newPath));
}
EnsureWriteAccess(newPath);
@@ -223,11 +235,9 @@ namespace Emby.Server.Implementations.AppBase
{
var file = Path.Combine(path, Guid.NewGuid().ToString());
File.WriteAllText(file, string.Empty);
- FileSystem.DeleteFile(file);
+ _fileSystem.DeleteFile(file);
}
- private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
-
private string GetConfigurationFile(string key)
{
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLowerInvariant() + ".xml");
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 120aade39..09847b2f8 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
+using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
@@ -107,9 +108,9 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
using ServiceStack;
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
@@ -385,7 +386,7 @@ namespace Emby.Server.Implementations
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
- NetworkManager.NetworkChanged += NetworkManager_NetworkChanged;
+ NetworkManager.NetworkChanged += OnNetworkChanged;
}
public string ExpandVirtualPath(string path)
@@ -409,7 +410,7 @@ namespace Emby.Server.Implementations
return ServerConfigurationManager.Configuration.LocalNetworkSubnets;
}
- private void NetworkManager_NetworkChanged(object sender, EventArgs e)
+ private void OnNetworkChanged(object sender, EventArgs e)
{
_validAddressResults.Clear();
}
@@ -417,10 +418,10 @@ namespace Emby.Server.Implementations
public string ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
/// <summary>
- /// Gets the current application user agent
+ /// Gets the current application user agent.
/// </summary>
/// <value>The application user agent.</value>
- public string ApplicationUserAgent => Name.Replace(' ','-') + '/' + ApplicationVersion;
+ public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersion;
/// <summary>
/// Gets the email address for use within a comment section of a user agent field.
@@ -428,14 +429,11 @@ namespace Emby.Server.Implementations
/// </summary>
public string ApplicationUserAgentAddress { get; } = "team@jellyfin.org";
- private string _productName;
-
/// <summary>
- /// Gets the current application name
+ /// Gets the current application name.
/// </summary>
/// <value>The application name.</value>
- public string ApplicationProductName
- => _productName ?? (_productName = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName);
+ public string ApplicationProductName { get; } = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName;
private DeviceId _deviceId;
@@ -469,8 +467,8 @@ namespace Emby.Server.Implementations
/// <summary>
/// Creates an instance of type and resolves all constructor dependencies
/// </summary>
- /// /// <typeparam name="T">The type</typeparam>
- /// <returns>T</returns>
+ /// /// <typeparam name="T">The type.</typeparam>
+ /// <returns>T.</returns>
public T CreateInstance<T>()
=> ActivatorUtilities.CreateInstance<T>(_serviceProvider);
@@ -603,10 +601,15 @@ namespace Emby.Server.Implementations
foreach (var plugin in Plugins)
{
- pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
+ pluginBuilder.AppendLine(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "{0} {1}",
+ plugin.Name,
+ plugin.Version));
}
- Logger.LogInformation("Plugins: {plugins}", pluginBuilder.ToString());
+ Logger.LogInformation("Plugins: {Plugins}", pluginBuilder.ToString());
}
DiscoverTypes();
@@ -628,7 +631,7 @@ namespace Emby.Server.Implementations
if (EnableHttps && Certificate != null)
{
- options.ListenAnyIP(HttpsPort, listenOptions => { listenOptions.UseHttps(Certificate); });
+ options.ListenAnyIP(HttpsPort, listenOptions => listenOptions.UseHttps(Certificate));
}
})
.UseContentRoot(contentRoot)
@@ -642,6 +645,7 @@ namespace Emby.Server.Implementations
app.UseWebSockets();
app.UseResponseCompression();
+
// TODO app.UseMiddleware<WebSocketMiddleware>();
app.Use(ExecuteWebsocketHandlerAsync);
app.Use(ExecuteHttpHandlerAsync);
@@ -675,7 +679,7 @@ namespace Emby.Server.Implementations
var localPath = context.Request.Path.ToString();
var req = new WebSocketSharpRequest(request, response, request.Path, Logger);
- await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, CancellationToken.None).ConfigureAwait(false);
+ await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, context.RequestAborted).ConfigureAwait(false);
}
public static IStreamHelper StreamHelper { get; set; }
@@ -784,7 +788,7 @@ namespace Emby.Server.Implementations
HttpServer = new HttpListenerHost(
this,
- LoggerFactory,
+ LoggerFactory.CreateLogger<HttpListenerHost>(),
ServerConfigurationManager,
_configuration,
NetworkManager,
@@ -872,7 +876,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IAuthorizationContext>(authContext);
serviceCollection.AddSingleton<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
- AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, SessionManager, NetworkManager);
+ AuthService = new AuthService(authContext, ServerConfigurationManager, SessionManager, NetworkManager);
serviceCollection.AddSingleton(AuthService);
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
@@ -1043,8 +1047,8 @@ namespace Emby.Server.Implementations
.Cast<IServerEntryPoint>()
.ToList();
- await Task.WhenAll(StartEntryPoints(entries, true));
- await Task.WhenAll(StartEntryPoints(entries, false));
+ await Task.WhenAll(StartEntryPoints(entries, true)).ConfigureAwait(false);
+ await Task.WhenAll(StartEntryPoints(entries, false)).ConfigureAwait(false);
}
/// <summary>
@@ -1219,7 +1223,7 @@ namespace Emby.Server.Implementations
// Generate self-signed cert
var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns);
- var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx");
+ var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N", CultureInfo.InvariantCulture) + ".pfx");
const string Password = "embycert";
return new CertificateInfo
@@ -1457,15 +1461,10 @@ namespace Emby.Server.Implementations
};
}
- public WakeOnLanInfo[] GetWakeOnLanInfo()
- {
- return NetworkManager.GetMacAddresses()
- .Select(i => new WakeOnLanInfo
- {
- MacAddress = i
- })
- .ToArray();
- }
+ public IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo()
+ => NetworkManager.GetMacAddresses()
+ .Select(i => new WakeOnLanInfo(i))
+ .ToList();
public async Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken)
{
@@ -1481,6 +1480,7 @@ namespace Emby.Server.Implementations
{
wanAddress = GetWanApiUrl(ServerConfigurationManager.Configuration.WanDdns);
}
+
return new PublicSystemInfo
{
Version = ApplicationVersion,
@@ -1546,14 +1546,32 @@ namespace Emby.Server.Implementations
return null;
}
- public string GetLocalApiUrl(IpAddressInfo ipAddress)
+ /// <summary>
+ /// Removes the scope id from IPv6 addresses.
+ /// </summary>
+ /// <param name="address">The IPv6 address.</param>
+ /// <returns>The IPv6 address without the scope id.</returns>
+ private string RemoveScopeId(string address)
{
- if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ var index = address.IndexOf('%');
+ if (index == -1)
{
- return GetLocalApiUrl("[" + ipAddress.Address + "]");
+ return address;
}
- return GetLocalApiUrl(ipAddress.Address);
+ return address.Substring(0, index);
+ }
+
+ public string GetLocalApiUrl(IPAddress ipAddress)
+ {
+ if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ var str = RemoveScopeId(ipAddress.ToString());
+
+ return GetLocalApiUrl("[" + str + "]");
+ }
+
+ return GetLocalApiUrl(ipAddress.ToString());
}
public string GetLocalApiUrl(string host)
@@ -1564,19 +1582,22 @@ namespace Emby.Server.Implementations
host,
HttpsPort.ToString(CultureInfo.InvariantCulture));
}
+
return string.Format("http://{0}:{1}",
host,
HttpPort.ToString(CultureInfo.InvariantCulture));
}
- public string GetWanApiUrl(IpAddressInfo ipAddress)
+ public string GetWanApiUrl(IPAddress ipAddress)
{
- if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- return GetWanApiUrl("[" + ipAddress.Address + "]");
+ var str = RemoveScopeId(ipAddress.ToString());
+
+ return GetWanApiUrl("[" + str + "]");
}
- return GetWanApiUrl(ipAddress.Address);
+ return GetWanApiUrl(ipAddress.ToString());
}
public string GetWanApiUrl(string host)
@@ -1587,17 +1608,18 @@ namespace Emby.Server.Implementations
host,
ServerConfigurationManager.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture));
}
+
return string.Format("http://{0}:{1}",
host,
ServerConfigurationManager.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture));
}
- public Task<List<IpAddressInfo>> GetLocalIpAddresses(CancellationToken cancellationToken)
+ public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)
{
return GetLocalIpAddressesInternal(true, 0, cancellationToken);
}
- private async Task<List<IpAddressInfo>> GetLocalIpAddressesInternal(bool allowLoopback, int limit, CancellationToken cancellationToken)
+ private async Task<List<IPAddress>> GetLocalIpAddressesInternal(bool allowLoopback, int limit, CancellationToken cancellationToken)
{
var addresses = ServerConfigurationManager
.Configuration
@@ -1611,13 +1633,13 @@ namespace Emby.Server.Implementations
addresses.AddRange(NetworkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
}
- var resultList = new List<IpAddressInfo>();
+ var resultList = new List<IPAddress>();
foreach (var address in addresses)
{
if (!allowLoopback)
{
- if (address.Equals(IpAddressInfo.Loopback) || address.Equals(IpAddressInfo.IPv6Loopback))
+ if (address.Equals(IPAddress.Loopback) || address.Equals(IPAddress.IPv6Loopback))
{
continue;
}
@@ -1638,7 +1660,7 @@ namespace Emby.Server.Implementations
return resultList;
}
- private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
+ private IPAddress NormalizeConfiguredLocalAddress(string address)
{
var index = address.Trim('/').IndexOf('/');
@@ -1647,7 +1669,7 @@ namespace Emby.Server.Implementations
address = address.Substring(index + 1);
}
- if (NetworkManager.TryParseIpAddress(address.Trim('/'), out IpAddressInfo result))
+ if (IPAddress.TryParse(address.Trim('/'), out IPAddress result))
{
return result;
}
@@ -1657,10 +1679,10 @@ namespace Emby.Server.Implementations
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
- private async Task<bool> IsIpAddressValidAsync(IpAddressInfo address, CancellationToken cancellationToken)
+ private async Task<bool> IsIpAddressValidAsync(IPAddress address, CancellationToken cancellationToken)
{
- if (address.Equals(IpAddressInfo.Loopback) ||
- address.Equals(IpAddressInfo.IPv6Loopback))
+ if (address.Equals(IPAddress.Loopback) ||
+ address.Equals(IPAddress.IPv6Loopback))
{
return true;
}
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index e9961e8bd..8e5f5b561 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -206,7 +207,7 @@ namespace Emby.Server.Implementations.Channels
try
{
- return GetChannelProvider(i).IsEnabledFor(user.Id.ToString("N"));
+ return GetChannelProvider(i).IsEnabledFor(user.Id.ToString("N", CultureInfo.InvariantCulture));
}
catch
{
@@ -511,7 +512,7 @@ namespace Emby.Server.Implementations.Channels
IncludeItemTypes = new[] { typeof(Channel).Name },
OrderBy = new ValueTuple<string, SortOrder>[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }
- }).Select(i => GetChannelFeatures(i.ToString("N"))).ToArray();
+ }).Select(i => GetChannelFeatures(i.ToString("N", CultureInfo.InvariantCulture))).ToArray();
}
public ChannelFeatures GetChannelFeatures(string id)
@@ -552,7 +553,7 @@ namespace Emby.Server.Implementations.Channels
SupportsSortOrderToggle = features.SupportsSortOrderToggle,
SupportsLatestMedia = supportsLatest,
Name = channel.Name,
- Id = channel.Id.ToString("N"),
+ Id = channel.Id.ToString("N", CultureInfo.InvariantCulture),
SupportsContentDownloading = features.SupportsContentDownloading,
AutoRefreshLevels = features.AutoRefreshLevels
};
@@ -740,7 +741,7 @@ namespace Emby.Server.Implementations.Channels
bool sortDescending,
CancellationToken cancellationToken)
{
- var userId = user == null ? null : user.Id.ToString("N");
+ var userId = user == null ? null : user.Id.ToString("N", CultureInfo.InvariantCulture);
var cacheLength = CacheLength;
var cachePath = GetChannelDataCachePath(channel, userId, externalFolderId, sortField, sortDescending);
@@ -836,7 +837,7 @@ namespace Emby.Server.Implementations.Channels
ChannelItemSortField? sortField,
bool sortDescending)
{
- var channelId = GetInternalChannelId(channel.Name).ToString("N");
+ var channelId = GetInternalChannelId(channel.Name).ToString("N", CultureInfo.InvariantCulture);
var userCacheKey = string.Empty;
@@ -846,10 +847,10 @@ namespace Emby.Server.Implementations.Channels
userCacheKey = hasCacheKey.GetCacheKey(userId) ?? string.Empty;
}
- var filename = string.IsNullOrEmpty(externalFolderId) ? "root" : externalFolderId.GetMD5().ToString("N");
+ var filename = string.IsNullOrEmpty(externalFolderId) ? "root" : externalFolderId.GetMD5().ToString("N", CultureInfo.InvariantCulture);
filename += userCacheKey;
- var version = ((channel.DataVersion ?? string.Empty) + "2").GetMD5().ToString("N");
+ var version = ((channel.DataVersion ?? string.Empty) + "2").GetMD5().ToString("N", CultureInfo.InvariantCulture);
if (sortField.HasValue)
{
@@ -860,7 +861,7 @@ namespace Emby.Server.Implementations.Channels
filename += "-sortDescending";
}
- filename = filename.GetMD5().ToString("N");
+ filename = filename.GetMD5().ToString("N", CultureInfo.InvariantCulture);
return Path.Combine(_config.ApplicationPaths.CachePath,
"channels",
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index 2b99e0ddf..bb5057b1c 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -182,7 +183,7 @@ namespace Emby.Server.Implementations.Collections
public void AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
{
- AddToCollection(collectionId, ids.Select(i => i.ToString("N")), true, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)));
+ AddToCollection(collectionId, ids.Select(i => i.ToString("N", CultureInfo.InvariantCulture)), true, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)));
}
private void AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index 9bc60972a..62408ee70 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -6,8 +6,8 @@ namespace Emby.Server.Implementations
{
public static readonly Dictionary<string, string> Configuration = new Dictionary<string, string>
{
- {"HttpListenerHost:DefaultRedirectPath", "web/index.html"},
- {"MusicBrainz:BaseUrl", "https://www.musicbrainz.org"}
+ { "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
+ { "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" }
};
}
}
diff --git a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
index 6d7193ce2..f726dae2e 100644
--- a/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
+++ b/Emby.Server.Implementations/Cryptography/CryptographyProvider.cs
@@ -8,7 +8,7 @@ using MediaBrowser.Model.Cryptography;
namespace Emby.Server.Implementations.Cryptography
{
- public class CryptographyProvider : ICryptoProvider
+ public class CryptographyProvider : ICryptoProvider, IDisposable
{
private static readonly HashSet<string> _supportedHashMethods = new HashSet<string>()
{
@@ -28,26 +28,28 @@ namespace Emby.Server.Implementations.Cryptography
"System.Security.Cryptography.SHA512"
};
- public string DefaultHashMethod => "PBKDF2";
-
private RandomNumberGenerator _randomNumberGenerator;
private const int _defaultIterations = 1000;
+ private bool _disposed = false;
+
public CryptographyProvider()
{
- //FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto
- //Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
- //there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
- //Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1
+ // FIXME: When we get DotNet Standard 2.1 we need to revisit how we do the crypto
+ // Currently supported hash methods from https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptoconfig?view=netcore-2.1
+ // there might be a better way to autogenerate this list as dotnet updates, but I couldn't find one
+ // Please note the default method of PBKDF2 is not included, it cannot be used to generate hashes cleanly as it is actually a pbkdf with sha1
_randomNumberGenerator = RandomNumberGenerator.Create();
}
+ public string DefaultHashMethod => "PBKDF2";
+
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
public Guid GetMD5(string str)
- {
- return new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
- }
+ => new Guid(ComputeMD5(Encoding.Unicode.GetBytes(str)));
+ [Obsolete("Use System.Security.Cryptography.SHA1 directly")]
public byte[] ComputeSHA1(byte[] bytes)
{
using (var provider = SHA1.Create())
@@ -56,6 +58,7 @@ namespace Emby.Server.Implementations.Cryptography
}
}
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
public byte[] ComputeMD5(Stream str)
{
using (var provider = MD5.Create())
@@ -64,6 +67,7 @@ namespace Emby.Server.Implementations.Cryptography
}
}
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
public byte[] ComputeMD5(byte[] bytes)
{
using (var provider = MD5.Create())
@@ -73,9 +77,7 @@ namespace Emby.Server.Implementations.Cryptography
}
public IEnumerable<string> GetSupportedHashMethods()
- {
- return _supportedHashMethods;
- }
+ => _supportedHashMethods;
private byte[] PBKDF2(string method, byte[] bytes, byte[] salt, int iterations)
{
@@ -93,14 +95,10 @@ namespace Emby.Server.Implementations.Cryptography
}
public byte[] ComputeHash(string hashMethod, byte[] bytes)
- {
- return ComputeHash(hashMethod, bytes, Array.Empty<byte>());
- }
+ => ComputeHash(hashMethod, bytes, Array.Empty<byte>());
public byte[] ComputeHashWithDefaultMethod(byte[] bytes)
- {
- return ComputeHash(DefaultHashMethod, bytes);
- }
+ => ComputeHash(DefaultHashMethod, bytes);
public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt)
{
@@ -125,37 +123,27 @@ namespace Emby.Server.Implementations.Cryptography
}
}
}
- else
- {
- throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
- }
+
+ throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
+
}
public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
- {
- return PBKDF2(DefaultHashMethod, bytes, salt, _defaultIterations);
- }
+ => PBKDF2(DefaultHashMethod, bytes, salt, _defaultIterations);
public byte[] ComputeHash(PasswordHash hash)
{
int iterations = _defaultIterations;
if (!hash.Parameters.ContainsKey("iterations"))
{
- hash.Parameters.Add("iterations", _defaultIterations.ToString(CultureInfo.InvariantCulture));
+ hash.Parameters.Add("iterations", iterations.ToString(CultureInfo.InvariantCulture));
}
- else
+ else if (!int.TryParse(hash.Parameters["iterations"], out iterations))
{
- try
- {
- iterations = int.Parse(hash.Parameters["iterations"]);
- }
- catch (Exception e)
- {
- throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}", e);
- }
+ throw new InvalidDataException($"Couldn't successfully parse iterations value from string: {hash.Parameters["iterations"]}");
}
- return PBKDF2(hash.Id, hash.HashBytes, hash.SaltBytes, iterations);
+ return PBKDF2(hash.Id, hash.Hash, hash.Salt, iterations);
}
public byte[] GenerateSalt()
@@ -164,5 +152,29 @@ namespace Emby.Server.Implementations.Cryptography
_randomNumberGenerator.GetBytes(salt);
return salt;
}
+
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ _randomNumberGenerator.Dispose();
+ }
+
+ _randomNumberGenerator = null;
+
+ _disposed = true;
+ }
}
}
diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
index 01ef9851d..87096e72f 100644
--- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Threading;
using MediaBrowser.Common.Configuration;
@@ -182,7 +183,7 @@ namespace Emby.Server.Implementations.Data
return new DisplayPreferences
{
- Id = guidId.ToString("N")
+ Id = guidId.ToString("N", CultureInfo.InvariantCulture)
};
}
}
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 1cefcec7c..bb4c34f02 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -696,7 +696,7 @@ namespace Emby.Server.Implementations.Data
saveItemStatement.TryBindNull("@EndDate");
}
- saveItemStatement.TryBind("@ChannelId", item.ChannelId.Equals(Guid.Empty) ? null : item.ChannelId.ToString("N"));
+ saveItemStatement.TryBind("@ChannelId", item.ChannelId.Equals(Guid.Empty) ? null : item.ChannelId.ToString("N", CultureInfo.InvariantCulture));
if (item is IHasProgramAttributes hasProgramAttributes)
{
@@ -851,7 +851,7 @@ namespace Emby.Server.Implementations.Data
}
else
{
- saveItemStatement.TryBind("@TopParentId", topParent.Id.ToString("N"));
+ saveItemStatement.TryBind("@TopParentId", topParent.Id.ToString("N", CultureInfo.InvariantCulture));
}
if (item is Trailer trailer && trailer.TrailerTypes.Length > 0)
@@ -3548,12 +3548,12 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("ChannelId=@ChannelId");
if (statement != null)
{
- statement.TryBind("@ChannelId", query.ChannelIds[0].ToString("N"));
+ statement.TryBind("@ChannelId", query.ChannelIds[0].ToString("N", CultureInfo.InvariantCulture));
}
}
else if (query.ChannelIds.Length > 1)
{
- var inClause = string.Join(",", query.ChannelIds.Select(i => "'" + i.ToString("N") + "'"));
+ var inClause = string.Join(",", query.ChannelIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
whereClauses.Add($"ChannelId in ({inClause})");
}
@@ -4537,12 +4537,12 @@ namespace Emby.Server.Implementations.Data
}
if (statement != null)
{
- statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N"));
+ statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture));
}
}
else if (queryTopParentIds.Length > 1)
{
- var val = string.Join(",", queryTopParentIds.Select(i => "'" + i.ToString("N") + "'"));
+ var val = string.Join(",", queryTopParentIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
if (enableItemsByName && includedItemByNameTypes.Count == 1)
{
@@ -4574,7 +4574,7 @@ namespace Emby.Server.Implementations.Data
}
if (query.AncestorIds.Length > 1)
{
- var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N") + "'"));
+ var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause));
}
if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey))
@@ -4637,7 +4637,7 @@ namespace Emby.Server.Implementations.Data
foreach (var folderId in query.BoxSetLibraryFolders)
{
- folderIdQueries.Add("data like '%" + folderId.ToString("N") + "%'");
+ folderIdQueries.Add("data like '%" + folderId.ToString("N", CultureInfo.InvariantCulture) + "%'");
}
whereClauses.Add("(" + string.Join(" OR ", folderIdQueries) + ")");
@@ -5161,7 +5161,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
var ancestorId = ancestorIds[i];
statement.TryBind("@AncestorId" + index, ancestorId.ToGuidBlob());
- statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N"));
+ statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture));
}
statement.Reset();
@@ -5579,6 +5579,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
{
counts.TrailerCount = value;
}
+
counts.ItemCount += value;
}
diff --git a/Emby.Server.Implementations/Devices/DeviceId.cs b/Emby.Server.Implementations/Devices/DeviceId.cs
index 495c3436a..7344dc72f 100644
--- a/Emby.Server.Implementations/Devices/DeviceId.cs
+++ b/Emby.Server.Implementations/Devices/DeviceId.cs
@@ -1,8 +1,8 @@
using System;
+using System.Globalization;
using System.IO;
using System.Text;
using MediaBrowser.Common.Configuration;
-using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Devices
@@ -67,7 +67,7 @@ namespace Emby.Server.Implementations.Devices
private static string GetNewId()
{
- return Guid.NewGuid().ToString("N");
+ return Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
private string GetDeviceId()
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index 7d6529a67..d1704b373 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Entities;
@@ -195,7 +195,7 @@ namespace Emby.Server.Implementations.Devices
private string GetDevicePath(string id)
{
- return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N"));
+ return Path.Combine(GetDevicesPath(), id.GetMD5().ToString("N", CultureInfo.InvariantCulture));
}
public ContentUploadHistory GetCameraUploadHistory(string deviceId)
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 2f1b60be9..6e7aa1313 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -213,7 +214,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.DisplayPreferencesId))
{
- dto.DisplayPreferencesId = item.DisplayPreferencesId.ToString("N");
+ dto.DisplayPreferencesId = item.DisplayPreferencesId.ToString("N", CultureInfo.InvariantCulture);
}
if (user != null)
@@ -444,7 +445,7 @@ namespace Emby.Server.Implementations.Dto
/// <exception cref="ArgumentNullException">item</exception>
public string GetDtoId(BaseItem item)
{
- return item.Id.ToString("N");
+ return item.Id.ToString("N", CultureInfo.InvariantCulture);
}
private static void SetBookProperties(BaseItemDto dto, Book item)
@@ -608,7 +609,7 @@ namespace Emby.Server.Implementations.Dto
if (dictionary.TryGetValue(person.Name, out Person entity))
{
baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary);
- baseItemPerson.Id = entity.Id.ToString("N");
+ baseItemPerson.Id = entity.Id.ToString("N", CultureInfo.InvariantCulture);
list.Add(baseItemPerson);
}
}
@@ -893,7 +894,7 @@ namespace Emby.Server.Implementations.Dto
//var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
//{
// EnableTotalRecordCount = false,
- // ItemIds = new[] { item.Id.ToString("N") }
+ // ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
//});
//dto.ArtistItems = artistItems.Items
@@ -903,7 +904,7 @@ namespace Emby.Server.Implementations.Dto
// return new NameIdPair
// {
// Name = artist.Name,
- // Id = artist.Id.ToString("N")
+ // Id = artist.Id.ToString("N", CultureInfo.InvariantCulture)
// };
// })
// .ToList();
@@ -946,7 +947,7 @@ namespace Emby.Server.Implementations.Dto
//var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
//{
// EnableTotalRecordCount = false,
- // ItemIds = new[] { item.Id.ToString("N") }
+ // ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
//});
//dto.AlbumArtists = artistItems.Items
@@ -956,7 +957,7 @@ namespace Emby.Server.Implementations.Dto
// return new NameIdPair
// {
// Name = artist.Name,
- // Id = artist.Id.ToString("N")
+ // Id = artist.Id.ToString("N", CultureInfo.InvariantCulture)
// };
// })
// .ToList();
@@ -1044,7 +1045,7 @@ namespace Emby.Server.Implementations.Dto
}
else
{
- string id = item.Id.ToString("N");
+ string id = item.Id.ToString("N", CultureInfo.InvariantCulture);
mediaStreams = dto.MediaSources.Where(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase))
.SelectMany(i => i.MediaStreams)
.ToArray();
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 49015a07e..f07f8e3bf 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
+ <PackageReference Include="IPNetwork2" Version="2.4.0.126" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
@@ -43,6 +44,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index 8369f4f59..9c0db2cf5 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -100,7 +100,7 @@ namespace Emby.Server.Implementations.EntryPoints
_lastProgressMessageTimes[item.Id] = DateTime.UtcNow;
var dict = new Dictionary<string, string>();
- dict["ItemId"] = item.Id.ToString("N");
+ dict["ItemId"] = item.Id.ToString("N", CultureInfo.InvariantCulture);
dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture);
try
@@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.EntryPoints
foreach (var collectionFolder in collectionFolders)
{
var collectionFolderDict = new Dictionary<string, string>();
- collectionFolderDict["ItemId"] = collectionFolder.Id.ToString("N");
+ collectionFolderDict["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture);
collectionFolderDict["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture);
try
@@ -378,15 +378,15 @@ namespace Emby.Server.Implementations.EntryPoints
return new LibraryUpdateInfo
{
- ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
+ ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
- ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
+ ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
- ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
+ ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
- FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
+ FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
- FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
+ FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(),
CollectionFolders = GetTopParentIds(newAndRemoved, allUserRootChildren).ToArray()
};
@@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.EntryPoints
var collectionFolders = _libraryManager.GetCollectionFolders(item, allUserRootChildren);
foreach (var folder in allUserRootChildren)
{
- list.Add(folder.Id.ToString("N"));
+ list.Add(folder.Id.ToString("N", CultureInfo.InvariantCulture));
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
index 091dd6a45..141e72958 100644
--- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Plugins;
@@ -134,7 +135,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// <param name="e">The e.</param>
void userManager_UserDeleted(object sender, GenericEventArgs<User> e)
{
- SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N"));
+ SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture));
}
void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)
diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
index a5badacee..bae3422ff 100644
--- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -8,7 +9,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
@@ -125,12 +125,12 @@ namespace Emby.Server.Implementations.EntryPoints
.Select(i =>
{
var dto = _userDataManager.GetUserDataDto(i, user);
- dto.ItemId = i.Id.ToString("N");
+ dto.ItemId = i.Id.ToString("N", CultureInfo.InvariantCulture);
return dto;
})
.ToArray();
- var userIdString = userId.ToString("N");
+ var userIdString = userId.ToString("N", CultureInfo.InvariantCulture);
return new UserDataChangeInfo
{
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index 331b5e29d..a933b53f5 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Concurrent;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
@@ -195,7 +196,7 @@ namespace Emby.Server.Implementations.HttpClientManager
}
var url = options.Url;
- var urlHash = url.ToLowerInvariant().GetMD5().ToString("N");
+ var urlHash = url.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index c6b7d31a8..2890cca7c 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -1,50 +1,43 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Net;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Server.Implementations.IO;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Services;
using Microsoft.Extensions.Logging;
+using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
public class FileWriter : IHttpResult
{
- private readonly IStreamHelper _streamHelper;
- private ILogger Logger { get; set; }
- private readonly IFileSystem _fileSystem;
-
- private string RangeHeader { get; set; }
- private bool IsHeadRequest { get; set; }
-
- private long RangeStart { get; set; }
- private long RangeEnd { get; set; }
- private long RangeLength { get; set; }
- public long TotalContentLength { get; set; }
+ private static readonly CultureInfo UsCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
- public Action OnComplete { get; set; }
- public Action OnError { get; set; }
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- public List<Cookie> Cookies { get; private set; }
+ private static readonly string[] _skipLogExtensions = {
+ ".js",
+ ".html",
+ ".css"
+ };
- public FileShareMode FileShare { get; set; }
+ private readonly IStreamHelper _streamHelper;
+ private readonly ILogger _logger;
+ private readonly IFileSystem _fileSystem;
/// <summary>
/// The _options
/// </summary>
private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
+
/// <summary>
- /// Gets the options.
+ /// The _requested ranges
/// </summary>
- /// <value>The options.</value>
- public IDictionary<string, string> Headers => _options;
-
- public string Path { get; set; }
+ private List<KeyValuePair<long, long?>> _requestedRanges;
public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem, IStreamHelper streamHelper)
{
@@ -57,7 +50,7 @@ namespace Emby.Server.Implementations.HttpServer
_fileSystem = fileSystem;
Path = path;
- Logger = logger;
+ _logger = logger;
RangeHeader = rangeHeader;
Headers[HeaderNames.ContentType] = contentType;
@@ -80,39 +73,34 @@ namespace Emby.Server.Implementations.HttpServer
Cookies = new List<Cookie>();
}
- /// <summary>
- /// Sets the range values.
- /// </summary>
- private void SetRangeValues()
- {
- var requestedRange = RequestedRanges[0];
+ private string RangeHeader { get; set; }
- // If the requested range is "0-", we can optimize by just doing a stream copy
- if (!requestedRange.Value.HasValue)
- {
- RangeEnd = TotalContentLength - 1;
- }
- else
- {
- RangeEnd = requestedRange.Value.Value;
- }
+ private bool IsHeadRequest { get; set; }
- RangeStart = requestedRange.Key;
- RangeLength = 1 + RangeEnd - RangeStart;
+ private long RangeStart { get; set; }
- // Content-Length is the length of what we're serving, not the original content
- var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
- Headers[HeaderNames.ContentLength] = lengthString;
- var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
- Headers[HeaderNames.ContentRange] = rangeString;
+ private long RangeEnd { get; set; }
- Logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
- }
+ private long RangeLength { get; set; }
+
+ public long TotalContentLength { get; set; }
+
+ public Action OnComplete { get; set; }
+
+ public Action OnError { get; set; }
+
+ public List<Cookie> Cookies { get; private set; }
+
+ public FileShareMode FileShare { get; set; }
/// <summary>
- /// The _requested ranges
+ /// Gets the options.
/// </summary>
- private List<KeyValuePair<long, long?>> _requestedRanges;
+ /// <value>The options.</value>
+ public IDictionary<string, string> Headers => _options;
+
+ public string Path { get; set; }
+
/// <summary>
/// Gets the requested ranges.
/// </summary>
@@ -139,6 +127,7 @@ namespace Emby.Server.Implementations.HttpServer
{
start = long.Parse(vals[0], UsCulture);
}
+
if (!string.IsNullOrEmpty(vals[1]))
{
end = long.Parse(vals[1], UsCulture);
@@ -152,13 +141,50 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- private static readonly string[] SkipLogExtensions = {
- ".js",
- ".html",
- ".css"
- };
+ public string ContentType { get; set; }
+
+ public IRequest RequestContext { get; set; }
+
+ public object Response { get; set; }
+
+ public int Status { get; set; }
+
+ public HttpStatusCode StatusCode
+ {
+ get => (HttpStatusCode)Status;
+ set => Status = (int)value;
+ }
+
+ /// <summary>
+ /// Sets the range values.
+ /// </summary>
+ private void SetRangeValues()
+ {
+ var requestedRange = RequestedRanges[0];
+
+ // If the requested range is "0-", we can optimize by just doing a stream copy
+ if (!requestedRange.Value.HasValue)
+ {
+ RangeEnd = TotalContentLength - 1;
+ }
+ else
+ {
+ RangeEnd = requestedRange.Value.Value;
+ }
+
+ RangeStart = requestedRange.Key;
+ RangeLength = 1 + RangeEnd - RangeStart;
+
+ // Content-Length is the length of what we're serving, not the original content
+ var lengthString = RangeLength.ToString(CultureInfo.InvariantCulture);
+ Headers[HeaderNames.ContentLength] = lengthString;
+ var rangeString = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
+ Headers[HeaderNames.ContentRange] = rangeString;
- public async Task WriteToAsync(IResponse response, CancellationToken cancellationToken)
+ _logger.LogInformation("Setting range response values for {0}. RangeRequest: {1} Content-Length: {2}, Content-Range: {3}", Path, RangeHeader, lengthString, rangeString);
+ }
+
+ public async Task WriteToAsync(HttpResponse response, CancellationToken cancellationToken)
{
try
{
@@ -176,16 +202,16 @@ namespace Emby.Server.Implementations.HttpServer
{
var extension = System.IO.Path.GetExtension(path);
- if (extension == null || !SkipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+ if (extension == null || !_skipLogExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
- Logger.LogDebug("Transmit file {0}", path);
+ _logger.LogDebug("Transmit file {0}", path);
}
offset = 0;
count = 0;
}
- await response.TransmitFile(path, offset, count, FileShare, _fileSystem, _streamHelper, cancellationToken).ConfigureAwait(false);
+ await TransmitFile(response.Body, path, offset, count, FileShare, cancellationToken).ConfigureAwait(false);
}
finally
{
@@ -193,18 +219,32 @@ namespace Emby.Server.Implementations.HttpServer
}
}
- public string ContentType { get; set; }
-
- public IRequest RequestContext { get; set; }
+ public async Task TransmitFile(Stream stream, string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
+ {
+ var fileOpenOptions = FileOpenOptions.SequentialScan;
- public object Response { get; set; }
+ // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ fileOpenOptions |= FileOpenOptions.Asynchronous;
+ }
- public int Status { get; set; }
+ using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
+ {
+ if (offset > 0)
+ {
+ fs.Position = offset;
+ }
- public HttpStatusCode StatusCode
- {
- get => (HttpStatusCode)Status;
- set => Status = (int)value;
+ if (count > 0)
+ {
+ await _streamHelper.CopyToAsync(fs, stream, count, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await fs.CopyToAsync(stream, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
+ }
+ }
}
}
}
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index d8938964f..4c233456c 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Net;
@@ -30,11 +29,7 @@ namespace Emby.Server.Implementations.HttpServer
{
public class HttpListenerHost : IHttpServer, IDisposable
{
- private string DefaultRedirectPath { get; set; }
- public string[] UrlPrefixes { get; private set; }
-
- public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
-
+ private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
private readonly INetworkManager _networkManager;
private readonly IServerApplicationHost _appHost;
@@ -42,18 +37,15 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IXmlSerializer _xmlSerializer;
private readonly IHttpListener _socketListener;
private readonly Func<Type, Func<string, object>> _funcParseFn;
-
- public Action<IRequest, IResponse, object>[] ResponseFilters { get; set; }
-
+ private readonly string _defaultRedirectPath;
private readonly Dictionary<Type, Type> ServiceOperationsMap = new Dictionary<Type, Type>();
- public static HttpListenerHost Instance { get; protected set; }
-
private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
+ private bool _disposed = false;
public HttpListenerHost(
IServerApplicationHost applicationHost,
- ILoggerFactory loggerFactory,
+ ILogger<HttpListenerHost> logger,
IServerConfigurationManager config,
IConfiguration configuration,
INetworkManager networkManager,
@@ -62,9 +54,9 @@ namespace Emby.Server.Implementations.HttpServer
IHttpListener socketListener)
{
_appHost = applicationHost;
- Logger = loggerFactory.CreateLogger("HttpServer");
+ _logger = logger;
_config = config;
- DefaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
+ _defaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
_networkManager = networkManager;
_jsonSerializer = jsonSerializer;
_xmlSerializer = xmlSerializer;
@@ -74,12 +66,20 @@ namespace Emby.Server.Implementations.HttpServer
_funcParseFn = t => s => JsvReader.GetParseFn(t)(s);
Instance = this;
- ResponseFilters = Array.Empty<Action<IRequest, IResponse, object>>();
+ ResponseFilters = Array.Empty<Action<IRequest, HttpResponse, object>>();
}
+ public Action<IRequest, HttpResponse, object>[] ResponseFilters { get; set; }
+
+ public static HttpListenerHost Instance { get; protected set; }
+
+ public string[] UrlPrefixes { get; private set; }
+
public string GlobalResponse { get; set; }
- protected ILogger Logger { get; }
+ public ServiceController ServiceController { get; private set; }
+
+ public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
public object CreateInstance(Type type)
{
@@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.HttpServer
/// and no more processing should be done.
/// </summary>
/// <returns></returns>
- public void ApplyRequestFilters(IRequest req, IResponse res, object requestDto)
+ public void ApplyRequestFilters(IRequest req, HttpResponse res, object requestDto)
{
//Exec all RequestFilter attributes with Priority < 0
var attributes = GetRequestFilterAttributes(requestDto.GetType());
@@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.HttpServer
return;
}
- var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, Logger)
+ var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger)
{
OnReceive = ProcessWebSocketMessageReceived,
Url = e.Url,
@@ -215,16 +215,16 @@ namespace Emby.Server.Implementations.HttpServer
if (logExceptionStackTrace)
{
- Logger.LogError(ex, "Error processing request");
+ _logger.LogError(ex, "Error processing request");
}
else if (logExceptionMessage)
{
- Logger.LogError(ex.Message);
+ _logger.LogError(ex.Message);
}
var httpRes = httpReq.Response;
- if (httpRes.OriginalResponse.HasStarted)
+ if (httpRes.HasStarted)
{
return;
}
@@ -233,11 +233,11 @@ namespace Emby.Server.Implementations.HttpServer
httpRes.StatusCode = statusCode;
httpRes.ContentType = "text/html";
- await Write(httpRes, NormalizeExceptionMessage(ex.Message)).ConfigureAwait(false);
+ await httpRes.WriteAsync(NormalizeExceptionMessage(ex.Message)).ConfigureAwait(false);
}
catch (Exception errorEx)
{
- Logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
+ _logger.LogError(errorEx, "Error this.ProcessRequest(context)(Exception while writing error to the response)");
}
}
@@ -431,7 +431,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 503;
httpRes.ContentType = "text/plain";
- await Write(httpRes, "Server shutting down").ConfigureAwait(false);
+ await httpRes.WriteAsync("Server shutting down", cancellationToken).ConfigureAwait(false);
return;
}
@@ -439,7 +439,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 400;
httpRes.ContentType = "text/plain";
- await Write(httpRes, "Invalid host").ConfigureAwait(false);
+ await httpRes.WriteAsync("Invalid host", cancellationToken).ConfigureAwait(false);
return;
}
@@ -447,7 +447,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 403;
httpRes.ContentType = "text/plain";
- await Write(httpRes, "Forbidden").ConfigureAwait(false);
+ await httpRes.WriteAsync("Forbidden", cancellationToken).ConfigureAwait(false);
return;
}
@@ -460,28 +460,27 @@ namespace Emby.Server.Implementations.HttpServer
if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
{
httpRes.StatusCode = 200;
- httpRes.AddHeader("Access-Control-Allow-Origin", "*");
- httpRes.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
- httpRes.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
+ httpRes.Headers.Add("Access-Control-Allow-Origin", "*");
+ httpRes.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
+ httpRes.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization");
httpRes.ContentType = "text/plain";
- await Write(httpRes, string.Empty).ConfigureAwait(false);
+ await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false);
return;
}
urlToLog = GetUrlToLog(urlString);
- Logger.LogDebug("HTTP {HttpMethod} {Url} UserAgent: {UserAgent} \nHeaders: {@Headers}", urlToLog, httpReq.UserAgent ?? string.Empty, httpReq.HttpMethod, httpReq.Headers);
if (string.Equals(localPath, "/emby/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, DefaultRedirectPath);
+ httpRes.Redirect(_defaultRedirectPath);
return;
}
if (string.Equals(localPath, "/emby", StringComparison.OrdinalIgnoreCase) ||
string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, "emby/" + DefaultRedirectPath);
+ httpRes.Redirect("emby/" + _defaultRedirectPath);
return;
}
@@ -494,9 +493,10 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
{
- await Write(httpRes,
+ await httpRes.WriteAsync(
"<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
- newUrl + "\">" + newUrl + "</a></body></html>").ConfigureAwait(false);
+ newUrl + "\">" + newUrl + "</a></body></html>",
+ cancellationToken).ConfigureAwait(false);
return;
}
}
@@ -511,34 +511,35 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
{
- await Write(httpRes,
+ await httpRes.WriteAsync(
"<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" +
- newUrl + "\">" + newUrl + "</a></body></html>").ConfigureAwait(false);
+ newUrl + "\">" + newUrl + "</a></body></html>",
+ cancellationToken).ConfigureAwait(false);
return;
}
}
if (string.Equals(localPath, "/web", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, DefaultRedirectPath);
+ httpRes.Redirect(_defaultRedirectPath);
return;
}
if (string.Equals(localPath, "/web/", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, "../" + DefaultRedirectPath);
+ httpRes.Redirect("../" + _defaultRedirectPath);
return;
}
if (string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, DefaultRedirectPath);
+ httpRes.Redirect(_defaultRedirectPath);
return;
}
if (string.IsNullOrEmpty(localPath))
{
- RedirectToUrl(httpRes, "/" + DefaultRedirectPath);
+ httpRes.Redirect("/" + _defaultRedirectPath);
return;
}
@@ -546,12 +547,12 @@ namespace Emby.Server.Implementations.HttpServer
{
if (localPath.EndsWith("web/dashboard.html", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, "index.html#!/dashboard.html");
+ httpRes.Redirect("index.html#!/dashboard.html");
}
if (localPath.EndsWith("web/home.html", StringComparison.OrdinalIgnoreCase))
{
- RedirectToUrl(httpRes, "index.html");
+ httpRes.Redirect("index.html");
}
}
@@ -562,7 +563,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.StatusCode = 503;
httpRes.ContentType = "text/html";
- await Write(httpRes, GlobalResponse).ConfigureAwait(false);
+ await httpRes.WriteAsync(GlobalResponse, cancellationToken).ConfigureAwait(false);
return;
}
}
@@ -571,7 +572,7 @@ namespace Emby.Server.Implementations.HttpServer
if (handler != null)
{
- await handler.ProcessRequestAsync(this, httpReq, httpRes, Logger, cancellationToken).ConfigureAwait(false);
+ await handler.ProcessRequestAsync(this, httpReq, httpRes, _logger, cancellationToken).ConfigureAwait(false);
}
else
{
@@ -598,11 +599,7 @@ namespace Emby.Server.Implementations.HttpServer
var elapsed = stopWatch.Elapsed;
if (elapsed.TotalMilliseconds > 500)
{
- Logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
- }
- else
- {
- Logger.LogDebug("HTTP Response {StatusCode} to {RemoteIp}. Time: {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
+ _logger.LogWarning("HTTP Response {StatusCode} to {RemoteIp}. Time (slow): {Elapsed:g}. {Url}", httpRes.StatusCode, remoteIp, elapsed, urlToLog);
}
}
}
@@ -619,18 +616,11 @@ namespace Emby.Server.Implementations.HttpServer
return new ServiceHandler(restPath, contentType);
}
- Logger.LogError("Could not find handler for {PathInfo}", pathInfo);
+ _logger.LogError("Could not find handler for {PathInfo}", pathInfo);
return null;
}
- private static Task Write(IResponse response, string text)
- {
- var bOutput = Encoding.UTF8.GetBytes(text);
- response.OriginalResponse.ContentLength = bOutput.Length;
- return response.OutputStream.WriteAsync(bOutput, 0, bOutput.Length);
- }
-
- private void RedirectToSecureUrl(IHttpRequest httpReq, IResponse httpRes, string url)
+ private void RedirectToSecureUrl(IHttpRequest httpReq, HttpResponse httpRes, string url)
{
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
{
@@ -640,23 +630,11 @@ namespace Emby.Server.Implementations.HttpServer
Scheme = "https"
};
url = builder.Uri.ToString();
-
- RedirectToUrl(httpRes, url);
- }
- else
- {
- RedirectToUrl(httpRes, url);
}
- }
- public static void RedirectToUrl(IResponse httpRes, string url)
- {
- httpRes.StatusCode = 302;
- httpRes.AddHeader("Location", url);
+ httpRes.Redirect(url);
}
- public ServiceController ServiceController { get; private set; }
-
/// <summary>
/// Adds the rest handlers.
/// </summary>
@@ -672,9 +650,9 @@ namespace Emby.Server.Implementations.HttpServer
var types = services.Select(r => r.GetType());
ServiceController.Init(this, types);
- ResponseFilters = new Action<IRequest, IResponse, object>[]
+ ResponseFilters = new Action<IRequest, HttpResponse, object>[]
{
- new ResponseFilter(Logger).FilterResponse
+ new ResponseFilter(_logger).FilterResponse
};
}
@@ -772,24 +750,23 @@ namespace Emby.Server.Implementations.HttpServer
return "emby/emby/" + path;
}
- private bool _disposed;
- private readonly object _disposeLock = new object();
+ /// <inheritdoc />
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
- lock (_disposeLock)
+ if (disposing)
{
- if (_disposed) return;
-
- _disposed = true;
-
- if (disposing)
- {
- Stop();
- }
+ Stop();
}
+
+ _disposed = true;
}
/// <summary>
@@ -803,7 +780,7 @@ namespace Emby.Server.Implementations.HttpServer
return Task.CompletedTask;
}
- Logger.LogDebug("Websocket message received: {0}", result.MessageType);
+ _logger.LogDebug("Websocket message received: {0}", result.MessageType);
IEnumerable<Task> GetTasks()
{
@@ -815,10 +792,5 @@ namespace Emby.Server.Implementations.HttpServer
return Task.WhenAll(GetTasks());
}
-
- public void Dispose()
- {
- Dispose(true);
- }
}
}
diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
index 08f424757..3e731366e 100644
--- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
+++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
@@ -2,6 +2,7 @@ using System;
using System.Globalization;
using System.Text;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
@@ -9,7 +10,7 @@ namespace Emby.Server.Implementations.HttpServer
{
public class ResponseFilter
{
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+ private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
private readonly ILogger _logger;
public ResponseFilter(ILogger logger)
@@ -23,12 +24,12 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="req">The req.</param>
/// <param name="res">The res.</param>
/// <param name="dto">The dto.</param>
- public void FilterResponse(IRequest req, IResponse res, object dto)
+ public void FilterResponse(IRequest req, HttpResponse res, object dto)
{
// Try to prevent compatibility view
- res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
- res.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
- res.AddHeader("Access-Control-Allow-Origin", "*");
+ res.Headers.Add("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
+ res.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
+ res.Headers.Add("Access-Control-Allow-Origin", "*");
if (dto is Exception exception)
{
@@ -39,7 +40,7 @@ namespace Emby.Server.Implementations.HttpServer
var error = exception.Message.Replace(Environment.NewLine, " ");
error = RemoveControlCharacters(error);
- res.AddHeader("X-Application-Error-Code", error);
+ res.Headers.Add("X-Application-Error-Code", error);
}
}
@@ -54,12 +55,11 @@ namespace Emby.Server.Implementations.HttpServer
if (hasHeaders.Headers.TryGetValue(HeaderNames.ContentLength, out string contentLength)
&& !string.IsNullOrEmpty(contentLength))
{
- var length = long.Parse(contentLength, UsCulture);
+ var length = long.Parse(contentLength, _usCulture);
if (length > 0)
{
- res.OriginalResponse.ContentLength = length;
- res.SendChunked = false;
+ res.ContentLength = length;
}
}
}
@@ -72,9 +72,12 @@ namespace Emby.Server.Implementations.HttpServer
/// <returns>System.String.</returns>
public static string RemoveControlCharacters(string inString)
{
- if (inString == null) return null;
+ if (inString == null)
+ {
+ return null;
+ }
- var newString = new StringBuilder();
+ var newString = new StringBuilder(inString.Length);
foreach (var ch in inString)
{
@@ -83,6 +86,7 @@ namespace Emby.Server.Implementations.HttpServer
newString.Append(ch);
}
}
+
return newString.ToString();
}
}
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
index 1027883ed..3d3f67ca2 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -3,7 +3,6 @@ using System.Linq;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
@@ -13,28 +12,23 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
public class AuthService : IAuthService
{
+ private readonly IAuthorizationContext _authorizationContext;
+ private readonly ISessionManager _sessionManager;
private readonly IServerConfigurationManager _config;
+ private readonly INetworkManager _networkManager;
- public AuthService(IUserManager userManager, IAuthorizationContext authorizationContext, IServerConfigurationManager config, ISessionManager sessionManager, INetworkManager networkManager)
+ public AuthService(
+ IAuthorizationContext authorizationContext,
+ IServerConfigurationManager config,
+ ISessionManager sessionManager,
+ INetworkManager networkManager)
{
- AuthorizationContext = authorizationContext;
+ _authorizationContext = authorizationContext;
_config = config;
- SessionManager = sessionManager;
- UserManager = userManager;
- NetworkManager = networkManager;
+ _sessionManager = sessionManager;
+ _networkManager = networkManager;
}
- public IUserManager UserManager { get; private set; }
- public IAuthorizationContext AuthorizationContext { get; private set; }
- public ISessionManager SessionManager { get; private set; }
- public INetworkManager NetworkManager { get; private set; }
-
- /// <summary>
- /// Redirect the client to a specific URL if authentication failed.
- /// If this property is null, simply `401 Unauthorized` is returned.
- /// </summary>
- public string HtmlRedirect { get; set; }
-
public void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues)
{
ValidateUser(request, authAttribtues);
@@ -43,7 +37,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
private void ValidateUser(IRequest request, IAuthenticationAttributes authAttribtues)
{
// This code is executed before the service
- var auth = AuthorizationContext.GetAuthorizationInfo(request);
+ var auth = _authorizationContext.GetAuthorizationInfo(request);
if (!IsExemptFromAuthenticationToken(authAttribtues, request))
{
@@ -80,7 +74,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
!string.IsNullOrEmpty(auth.Client) &&
!string.IsNullOrEmpty(auth.Device))
{
- SessionManager.LogSessionActivity(auth.Client,
+ _sessionManager.LogSessionActivity(auth.Client,
auth.Version,
auth.DeviceId,
auth.Device,
@@ -89,7 +83,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
}
}
- private void ValidateUserAccess(User user, IRequest request,
+ private void ValidateUserAccess(
+ User user,
+ IRequest request,
IAuthenticationAttributes authAttribtues,
AuthorizationInfo auth)
{
@@ -101,7 +97,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
};
}
- if (!user.Policy.EnableRemoteAccess && !NetworkManager.IsInLocalNetwork(request.RemoteIp))
+ if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp))
{
throw new SecurityException("User account has been disabled.")
{
@@ -109,11 +105,11 @@ namespace Emby.Server.Implementations.HttpServer.Security
};
}
- if (!user.Policy.IsAdministrator &&
- !authAttribtues.EscapeParentalControl &&
- !user.IsParentalScheduleAllowed())
+ if (!user.Policy.IsAdministrator
+ && !authAttribtues.EscapeParentalControl
+ && !user.IsParentalScheduleAllowed())
{
- request.Response.AddHeader("X-Application-Error-Code", "ParentalControl");
+ request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl");
throw new SecurityException("This user account is not allowed access at this time.")
{
@@ -183,6 +179,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
};
}
}
+
if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
{
if (user == null || !user.Policy.EnableContentDeletion)
@@ -193,6 +190,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
};
}
}
+
if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
{
if (user == null || !user.Policy.EnableContentDownloading)
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 8517abed6..ae8371a32 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -555,7 +556,7 @@ namespace Emby.Server.Implementations.IO
throw new ArgumentNullException(nameof(file2));
}
- var temp1 = Path.Combine(_tempPath, Guid.NewGuid().ToString("N"));
+ var temp1 = Path.Combine(_tempPath, Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture));
// Copying over will fail against hidden files
SetHidden(file1, false);
diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
index 46f209b4b..d8faceadb 100644
--- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -89,7 +90,7 @@ namespace Emby.Server.Implementations.Images
ImageType imageType,
CancellationToken cancellationToken)
{
- var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N"));
+ var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture));
Directory.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension));
string outputPath = CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0);
diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
index a70077163..f1ae2fc9c 100644
--- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
@@ -5,7 +5,6 @@ using System.Text.RegularExpressions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library
@@ -17,12 +16,10 @@ namespace Emby.Server.Implementations.Library
{
private readonly ILibraryManager _libraryManager;
- private bool _ignoreDotPrefix;
-
/// <summary>
- /// Any folder named in this list will be ignored - can be added to at runtime for extensibility
+ /// Any folder named in this list will be ignored
/// </summary>
- public static readonly string[] IgnoreFolders =
+ private static readonly string[] _ignoreFolders =
{
"metadata",
"ps3_update",
@@ -43,25 +40,14 @@ namespace Emby.Server.Implementations.Library
"$RECYCLE.BIN",
"System Volume Information",
".grab",
-
- // macos
- ".AppleDouble"
-
};
public CoreResolutionIgnoreRule(ILibraryManager libraryManager)
{
_libraryManager = libraryManager;
-
- _ignoreDotPrefix = Environment.OSVersion.Platform != PlatformID.Win32NT;
}
- /// <summary>
- /// Shoulds the ignore.
- /// </summary>
- /// <param name="fileInfo">The file information.</param>
- /// <param name="parent">The parent.</param>
- /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+ /// <inheritdoc />
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent)
{
// Don't ignore top level folders
@@ -73,46 +59,17 @@ namespace Emby.Server.Implementations.Library
var filename = fileInfo.Name;
var path = fileInfo.FullName;
- // Handle mac .DS_Store
- // https://github.com/MediaBrowser/MediaBrowser/issues/427
- if (_ignoreDotPrefix)
+ // Ignore hidden files on UNIX
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT
+ && filename[0] == '.')
{
- if (filename.IndexOf('.') == 0)
- {
- return true;
- }
+ return true;
}
- // Ignore hidden files and folders
- //if (fileInfo.IsHidden)
- //{
- // if (parent == null)
- // {
- // var parentFolderName = Path.GetFileName(_fileSystem.GetDirectoryName(path));
-
- // if (string.Equals(parentFolderName, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- // {
- // return false;
- // }
- // if (string.Equals(parentFolderName, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- // {
- // return false;
- // }
- // }
-
- // // Sometimes these are marked hidden
- // if (_fileSystem.IsRootPath(path))
- // {
- // return false;
- // }
-
- // return true;
- //}
-
if (fileInfo.IsDirectory)
{
// Ignore any folders in our list
- if (IgnoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase))
+ if (_ignoreFolders.Contains(filename, StringComparer.OrdinalIgnoreCase))
{
return true;
}
@@ -120,8 +77,9 @@ namespace Emby.Server.Implementations.Library
if (parent != null)
{
// Ignore trailer folders but allow it at the collection level
- if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase) &&
- !(parent is AggregateFolder) && !(parent is UserRootFolder))
+ if (string.Equals(filename, BaseItem.TrailerFolderName, StringComparison.OrdinalIgnoreCase)
+ && !(parent is AggregateFolder)
+ && !(parent is UserRootFolder))
{
return true;
}
@@ -142,14 +100,15 @@ namespace Emby.Server.Implementations.Library
if (parent != null)
{
// Don't resolve these into audio files
- if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename))
+ if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename)
+ && _libraryManager.IsAudioFile(filename))
{
return true;
}
}
// Ignore samples
- Match m = Regex.Match(filename,@"\bsample\b",RegexOptions.IgnoreCase);
+ Match m = Regex.Match(filename, @"\bsample\b", RegexOptions.IgnoreCase);
return m.Success;
}
diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
index fe09b07ff..b07244fda 100644
--- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
+++ b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
@@ -11,9 +11,9 @@ namespace Emby.Server.Implementations.Library
public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser
{
private readonly ICryptoProvider _cryptographyProvider;
- public DefaultAuthenticationProvider(ICryptoProvider crypto)
+ public DefaultAuthenticationProvider(ICryptoProvider cryptographyProvider)
{
- _cryptographyProvider = crypto;
+ _cryptographyProvider = cryptographyProvider;
}
public string Name => "Default";
@@ -28,17 +28,17 @@ namespace Emby.Server.Implementations.Library
throw new NotImplementedException();
}
- // This is the verson that we need to use for local users. Because reasons.
+ // This is the version that we need to use for local users. Because reasons.
public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser)
{
bool success = false;
if (resolvedUser == null)
{
- throw new Exception("Invalid username or password");
+ throw new ArgumentNullException(nameof(resolvedUser));
}
// As long as jellyfin supports passwordless users, we need this little block here to accomodate
- if (IsPasswordEmpty(resolvedUser, password))
+ if (!HasPassword(resolvedUser) && string.IsNullOrEmpty(password))
{
return Task.FromResult(new ProviderAuthenticationResult
{
@@ -50,37 +50,24 @@ namespace Emby.Server.Implementations.Library
byte[] passwordbytes = Encoding.UTF8.GetBytes(password);
PasswordHash readyHash = new PasswordHash(resolvedUser.Password);
- byte[] calculatedHash;
- string calculatedHashString;
- if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id) || _cryptographyProvider.DefaultHashMethod == readyHash.Id)
+ if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id)
+ || _cryptographyProvider.DefaultHashMethod == readyHash.Id)
{
- if (string.IsNullOrEmpty(readyHash.Salt))
- {
- calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes);
- calculatedHashString = BitConverter.ToString(calculatedHash).Replace("-", string.Empty);
- }
- else
- {
- calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.SaltBytes);
- calculatedHashString = BitConverter.ToString(calculatedHash).Replace("-", string.Empty);
- }
+ byte[] calculatedHash = _cryptographyProvider.ComputeHash(readyHash.Id, passwordbytes, readyHash.Salt);
- if (calculatedHashString == readyHash.Hash)
+ if (calculatedHash.SequenceEqual(readyHash.Hash))
{
success = true;
- // throw new Exception("Invalid username or password");
}
}
else
{
- throw new Exception(string.Format($"Requested crypto method not available in provider: {readyHash.Id}"));
+ throw new AuthenticationException($"Requested crypto method not available in provider: {readyHash.Id}");
}
- // var success = string.Equals(GetPasswordHash(resolvedUser), GetHashedString(resolvedUser, password), StringComparison.OrdinalIgnoreCase);
-
if (!success)
{
- throw new Exception("Invalid username or password");
+ throw new AuthenticationException("Invalid username or password");
}
return Task.FromResult(new ProviderAuthenticationResult
@@ -98,29 +85,22 @@ namespace Emby.Server.Implementations.Library
return;
}
- if (!user.Password.Contains("$"))
+ if (user.Password.IndexOf('$') == -1)
{
string hash = user.Password;
user.Password = string.Format("$SHA1${0}", hash);
}
- if (user.EasyPassword != null && !user.EasyPassword.Contains("$"))
+ if (user.EasyPassword != null
+ && user.EasyPassword.IndexOf('$') == -1)
{
string hash = user.EasyPassword;
user.EasyPassword = string.Format("$SHA1${0}", hash);
}
}
- public Task<bool> HasPassword(User user)
- {
- var hasConfiguredPassword = !IsPasswordEmpty(user, GetPasswordHash(user));
- return Task.FromResult(hasConfiguredPassword);
- }
-
- private bool IsPasswordEmpty(User user, string password)
- {
- return (string.IsNullOrEmpty(user.Password) && string.IsNullOrEmpty(password));
- }
+ public bool HasPassword(User user)
+ => !string.IsNullOrEmpty(user.Password);
public Task ChangePassword(User user, string newPassword)
{
@@ -129,30 +109,24 @@ namespace Emby.Server.Implementations.Library
if (string.IsNullOrEmpty(user.Password))
{
PasswordHash newPasswordHash = new PasswordHash(_cryptographyProvider);
- newPasswordHash.SaltBytes = _cryptographyProvider.GenerateSalt();
- newPasswordHash.Salt = PasswordHash.ConvertToByteString(newPasswordHash.SaltBytes);
+ newPasswordHash.Salt = _cryptographyProvider.GenerateSalt();
newPasswordHash.Id = _cryptographyProvider.DefaultHashMethod;
- newPasswordHash.Hash = GetHashedStringChangeAuth(newPassword, newPasswordHash);
+ newPasswordHash.Hash = GetHashedChangeAuth(newPassword, newPasswordHash);
user.Password = newPasswordHash.ToString();
return Task.CompletedTask;
}
PasswordHash passwordHash = new PasswordHash(user.Password);
- if (passwordHash.Id == "SHA1" && string.IsNullOrEmpty(passwordHash.Salt))
+ if (passwordHash.Id == "SHA1"
+ && passwordHash.Salt.Length == 0)
{
- passwordHash.SaltBytes = _cryptographyProvider.GenerateSalt();
- passwordHash.Salt = PasswordHash.ConvertToByteString(passwordHash.SaltBytes);
+ passwordHash.Salt = _cryptographyProvider.GenerateSalt();
passwordHash.Id = _cryptographyProvider.DefaultHashMethod;
- passwordHash.Hash = GetHashedStringChangeAuth(newPassword, passwordHash);
+ passwordHash.Hash = GetHashedChangeAuth(newPassword, passwordHash);
}
else if (newPassword != null)
{
- passwordHash.Hash = GetHashedString(user, newPassword);
- }
-
- if (string.IsNullOrWhiteSpace(passwordHash.Hash))
- {
- throw new ArgumentNullException(nameof(passwordHash.Hash));
+ passwordHash.Hash = GetHashed(user, newPassword);
}
user.Password = passwordHash.ToString();
@@ -160,11 +134,6 @@ namespace Emby.Server.Implementations.Library
return Task.CompletedTask;
}
- public string GetPasswordHash(User user)
- {
- return user.Password;
- }
-
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
{
ConvertPasswordFormat(user);
@@ -190,13 +159,13 @@ namespace Emby.Server.Implementations.Library
return string.IsNullOrEmpty(user.EasyPassword)
? null
- : (new PasswordHash(user.EasyPassword)).Hash;
+ : PasswordHash.ConvertToByteString(new PasswordHash(user.EasyPassword).Hash);
}
- public string GetHashedStringChangeAuth(string newPassword, PasswordHash passwordHash)
+ internal byte[] GetHashedChangeAuth(string newPassword, PasswordHash passwordHash)
{
- passwordHash.HashBytes = Encoding.UTF8.GetBytes(newPassword);
- return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
+ passwordHash.Hash = Encoding.UTF8.GetBytes(newPassword);
+ return _cryptographyProvider.ComputeHash(passwordHash);
}
/// <summary>
@@ -215,10 +184,10 @@ namespace Emby.Server.Implementations.Library
passwordHash = new PasswordHash(user.Password);
}
- if (passwordHash.SaltBytes != null)
+ if (passwordHash.Salt != null)
{
// the password is modern format with PBKDF and we should take advantage of that
- passwordHash.HashBytes = Encoding.UTF8.GetBytes(str);
+ passwordHash.Hash = Encoding.UTF8.GetBytes(str);
return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash));
}
else
@@ -227,5 +196,31 @@ namespace Emby.Server.Implementations.Library
return PasswordHash.ConvertToByteString(_cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str)));
}
}
+
+ public byte[] GetHashed(User user, string str)
+ {
+ PasswordHash passwordHash;
+ if (string.IsNullOrEmpty(user.Password))
+ {
+ passwordHash = new PasswordHash(_cryptographyProvider);
+ }
+ else
+ {
+ ConvertPasswordFormat(user);
+ passwordHash = new PasswordHash(user.Password);
+ }
+
+ if (passwordHash.Salt != null)
+ {
+ // the password is modern format with PBKDF and we should take advantage of that
+ passwordHash.Hash = Encoding.UTF8.GetBytes(str);
+ return _cryptographyProvider.ComputeHash(passwordHash);
+ }
+ else
+ {
+ // the password has no salt and should be called with the older method for safety
+ return _cryptographyProvider.ComputeHash(passwordHash.Id, Encoding.UTF8.GetBytes(str));
+ }
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs b/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
index e218749d9..c7044820c 100644
--- a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
+++ b/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
@@ -1,132 +1,125 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Users;
-
-namespace Emby.Server.Implementations.Library
-{
- public class DefaultPasswordResetProvider : IPasswordResetProvider
- {
- public string Name => "Default Password Reset Provider";
-
- public bool IsEnabled => true;
-
- private readonly string _passwordResetFileBase;
- private readonly string _passwordResetFileBaseDir;
- private readonly string _passwordResetFileBaseName = "passwordreset";
-
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IUserManager _userManager;
- private readonly ICryptoProvider _crypto;
-
- public DefaultPasswordResetProvider(IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IUserManager userManager, ICryptoProvider cryptoProvider)
- {
- _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath;
- _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, _passwordResetFileBaseName);
- _jsonSerializer = jsonSerializer;
- _userManager = userManager;
- _crypto = cryptoProvider;
- }
-
- public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
- {
- SerializablePasswordReset spr;
- HashSet<string> usersreset = new HashSet<string>();
- foreach (var resetfile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{_passwordResetFileBaseName}*"))
- {
- using (var str = File.OpenRead(resetfile))
- {
- spr = await _jsonSerializer.DeserializeFromStreamAsync<SerializablePasswordReset>(str).ConfigureAwait(false);
- }
-
- if (spr.ExpirationDate < DateTime.Now)
- {
- File.Delete(resetfile);
- }
- else if (spr.Pin.Replace("-", "").Equals(pin.Replace("-", ""), StringComparison.InvariantCultureIgnoreCase))
- {
- var resetUser = _userManager.GetUserByName(spr.UserName);
- if (resetUser == null)
- {
- throw new Exception($"User with a username of {spr.UserName} not found");
- }
-
- await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
- usersreset.Add(resetUser.Name);
- File.Delete(resetfile);
- }
- }
-
- if (usersreset.Count < 1)
- {
- throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}");
- }
- else
- {
- return new PinRedeemResult
- {
- Success = true,
- UsersReset = usersreset.ToArray()
- };
- }
- }
-
- public async Task<ForgotPasswordResult> StartForgotPasswordProcess(MediaBrowser.Controller.Entities.User user, bool isInNetwork)
- {
- string pin = string.Empty;
- using (var cryptoRandom = System.Security.Cryptography.RandomNumberGenerator.Create())
- {
- byte[] bytes = new byte[4];
- cryptoRandom.GetBytes(bytes);
- pin = BitConverter.ToString(bytes);
- }
-
- DateTime expireTime = DateTime.Now.AddMinutes(30);
- string filePath = _passwordResetFileBase + user.InternalId + ".json";
- SerializablePasswordReset spr = new SerializablePasswordReset
- {
- ExpirationDate = expireTime,
- Pin = pin,
- PinFile = filePath,
- UserName = user.Name
- };
-
- try
- {
- using (FileStream fileStream = File.OpenWrite(filePath))
- {
- _jsonSerializer.SerializeToStream(spr, fileStream);
- await fileStream.FlushAsync().ConfigureAwait(false);
- }
- }
- catch (Exception e)
- {
- throw new Exception($"Error serializing or writing password reset for {user.Name} to location: {filePath}", e);
- }
-
- return new ForgotPasswordResult
- {
- Action = ForgotPasswordAction.PinCode,
- PinExpirationDate = expireTime,
- PinFile = filePath
- };
- }
-
- private class SerializablePasswordReset : PasswordPinCreationResult
- {
- public string Pin { get; set; }
-
- public string UserName { get; set; }
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Authentication;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Cryptography;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Users;
+
+namespace Emby.Server.Implementations.Library
+{
+ public class DefaultPasswordResetProvider : IPasswordResetProvider
+ {
+ public string Name => "Default Password Reset Provider";
+
+ public bool IsEnabled => true;
+
+ private readonly string _passwordResetFileBase;
+ private readonly string _passwordResetFileBaseDir;
+ private readonly string _passwordResetFileBaseName = "passwordreset";
+
+ private readonly IJsonSerializer _jsonSerializer;
+ private readonly IUserManager _userManager;
+ private readonly ICryptoProvider _crypto;
+
+ public DefaultPasswordResetProvider(IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IUserManager userManager, ICryptoProvider cryptoProvider)
+ {
+ _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath;
+ _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, _passwordResetFileBaseName);
+ _jsonSerializer = jsonSerializer;
+ _userManager = userManager;
+ _crypto = cryptoProvider;
+ }
+
+ public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
+ {
+ SerializablePasswordReset spr;
+ HashSet<string> usersreset = new HashSet<string>();
+ foreach (var resetfile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{_passwordResetFileBaseName}*"))
+ {
+ using (var str = File.OpenRead(resetfile))
+ {
+ spr = await _jsonSerializer.DeserializeFromStreamAsync<SerializablePasswordReset>(str).ConfigureAwait(false);
+ }
+
+ if (spr.ExpirationDate < DateTime.Now)
+ {
+ File.Delete(resetfile);
+ }
+ else if (spr.Pin.Replace("-", "").Equals(pin.Replace("-", ""), StringComparison.InvariantCultureIgnoreCase))
+ {
+ var resetUser = _userManager.GetUserByName(spr.UserName);
+ if (resetUser == null)
+ {
+ throw new Exception($"User with a username of {spr.UserName} not found");
+ }
+
+ await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
+ usersreset.Add(resetUser.Name);
+ File.Delete(resetfile);
+ }
+ }
+
+ if (usersreset.Count < 1)
+ {
+ throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}");
+ }
+ else
+ {
+ return new PinRedeemResult
+ {
+ Success = true,
+ UsersReset = usersreset.ToArray()
+ };
+ }
+ }
+
+ public async Task<ForgotPasswordResult> StartForgotPasswordProcess(MediaBrowser.Controller.Entities.User user, bool isInNetwork)
+ {
+ string pin = string.Empty;
+ using (var cryptoRandom = System.Security.Cryptography.RandomNumberGenerator.Create())
+ {
+ byte[] bytes = new byte[4];
+ cryptoRandom.GetBytes(bytes);
+ pin = BitConverter.ToString(bytes);
+ }
+
+ DateTime expireTime = DateTime.Now.AddMinutes(30);
+ string filePath = _passwordResetFileBase + user.InternalId + ".json";
+ SerializablePasswordReset spr = new SerializablePasswordReset
+ {
+ ExpirationDate = expireTime,
+ Pin = pin,
+ PinFile = filePath,
+ UserName = user.Name
+ };
+
+ using (FileStream fileStream = File.OpenWrite(filePath))
+ {
+ _jsonSerializer.SerializeToStream(spr, fileStream);
+ await fileStream.FlushAsync().ConfigureAwait(false);
+ }
+
+ return new ForgotPasswordResult
+ {
+ Action = ForgotPasswordAction.PinCode,
+ PinExpirationDate = expireTime,
+ PinFile = filePath
+ };
+ }
+
+ private class SerializablePasswordReset : PasswordPinCreationResult
+ {
+ public string Pin { get; set; }
+
+ public string UserName { get; set; }
+ }
+ }
+}
diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
index 45a33a296..a3c879f12 100644
--- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
+++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
@@ -26,7 +27,7 @@ namespace Emby.Server.Implementations.Library
EnableStreamSharing = false;
_closeFn = closeFn;
ConsumerCount = 1;
- UniqueId = Guid.NewGuid().ToString("N");
+ UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
public Task Close()
diff --git a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs b/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
index 25d233137..6956369dc 100644
--- a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
+++ b/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
@@ -1,6 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Entities;
@@ -16,12 +13,12 @@ namespace Emby.Server.Implementations.Library
public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
{
- throw new SecurityException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
+ throw new AuthenticationException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
}
- public Task<bool> HasPassword(User user)
+ public bool HasPassword(User user)
{
- return Task.FromResult(true);
+ return true;
}
public Task ChangePassword(User user, string newPassword)
@@ -31,7 +28,7 @@ namespace Emby.Server.Implementations.Library
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
{
- // Nothing here
+ // Nothing here
}
public string GetPasswordHash(User user)
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 4b5063ada..30ff855cc 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -1187,12 +1187,12 @@ namespace Emby.Server.Implementations.Library
if (libraryFolder != null && libraryFolder.HasImage(ImageType.Primary))
{
- info.PrimaryImageItemId = libraryFolder.Id.ToString("N");
+ info.PrimaryImageItemId = libraryFolder.Id.ToString("N", CultureInfo.InvariantCulture);
}
if (libraryFolder != null)
{
- info.ItemId = libraryFolder.Id.ToString("N");
+ info.ItemId = libraryFolder.Id.ToString("N", CultureInfo.InvariantCulture);
info.LibraryOptions = GetLibraryOptions(libraryFolder);
if (refreshQueue != null)
@@ -2135,12 +2135,12 @@ namespace Emby.Server.Implementations.Library
string viewType,
string sortName)
{
- var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N");
- var idValues = "38_namedview_" + name + user.Id.ToString("N") + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
+ var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N", CultureInfo.InvariantCulture);
+ var idValues = "38_namedview_" + name + user.Id.ToString("N", CultureInfo.InvariantCulture) + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
var id = GetNewItemId(idValues, typeof(UserView));
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
+ var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
var item = GetItemById(id) as UserView;
@@ -2271,7 +2271,7 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(name));
}
- var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N");
+ var parentIdString = parentId.Equals(Guid.Empty) ? null : parentId.ToString("N", CultureInfo.InvariantCulture);
var idValues = "37_namedview_" + name + (parentIdString ?? string.Empty) + (viewType ?? string.Empty);
if (!string.IsNullOrEmpty(uniqueId))
{
@@ -2280,7 +2280,7 @@ namespace Emby.Server.Implementations.Library
var id = GetNewItemId(idValues, typeof(UserView));
- var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
+ var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N", CultureInfo.InvariantCulture));
var item = GetItemById(id) as UserView;
diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
index c3082a78a..33e6f2434 100644
--- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs
+++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
@@ -40,7 +40,7 @@ namespace Emby.Server.Implementations.Library
var now = DateTime.UtcNow;
MediaInfo mediaInfo = null;
- var cacheFilePath = string.IsNullOrEmpty(cacheKey) ? null : Path.Combine(_appPaths.CachePath, "mediainfo", cacheKey.GetMD5().ToString("N") + ".json");
+ var cacheFilePath = string.IsNullOrEmpty(cacheKey) ? null : Path.Combine(_appPaths.CachePath, "mediainfo", cacheKey.GetMD5().ToString("N", CultureInfo.InvariantCulture) + ".json");
if (!string.IsNullOrEmpty(cacheKey))
{
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index 24ab8e761..d83e1fc02 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -269,7 +269,7 @@ namespace Emby.Server.Implementations.Library
private static void SetKeyProperties(IMediaSourceProvider provider, MediaSourceInfo mediaSource)
{
- var prefix = provider.GetType().FullName.GetMD5().ToString("N") + LiveStreamIdDelimeter;
+ var prefix = provider.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture) + LiveStreamIdDelimeter;
if (!string.IsNullOrEmpty(mediaSource.OpenToken) && !mediaSource.OpenToken.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
@@ -626,7 +626,7 @@ namespace Emby.Server.Implementations.Library
var now = DateTime.UtcNow;
MediaInfo mediaInfo = null;
- var cacheFilePath = string.IsNullOrEmpty(cacheKey) ? null : Path.Combine(_appPaths.CachePath, "mediainfo", cacheKey.GetMD5().ToString("N") + ".json");
+ var cacheFilePath = string.IsNullOrEmpty(cacheKey) ? null : Path.Combine(_appPaths.CachePath, "mediainfo", cacheKey.GetMD5().ToString("N", CultureInfo.InvariantCulture) + ".json");
if (!string.IsNullOrEmpty(cacheKey))
{
@@ -854,7 +854,7 @@ namespace Emby.Server.Implementations.Library
var keys = key.Split(new[] { LiveStreamIdDelimeter }, 2);
- var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), keys[0], StringComparison.OrdinalIgnoreCase));
+ var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), keys[0], StringComparison.OrdinalIgnoreCase));
var splitIndex = key.IndexOf(LiveStreamIdDelimeter);
var keyId = key.Substring(splitIndex + 1);
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 47c3e71d7..1b63b00a3 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -12,7 +12,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library.Resolvers.Movies
@@ -28,7 +27,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// <value>The priority.</value>
public override ResolverPriority Priority => ResolverPriority.Third;
- public MultiItemResolverResult ResolveMultiple(Folder parent,
+ public MultiItemResolverResult ResolveMultiple(
+ Folder parent,
List<FileSystemMetadata> files,
string collectionType,
IDirectoryService directoryService)
@@ -46,7 +46,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return result;
}
- private MultiItemResolverResult ResolveMultipleInternal(Folder parent,
+ private MultiItemResolverResult ResolveMultipleInternal(
+ Folder parent,
List<FileSystemMetadata> files,
string collectionType,
IDirectoryService directoryService)
@@ -91,7 +92,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return null;
}
- private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions, string collectionType, bool parseName)
+ private MultiItemResolverResult ResolveVideos<T>(
+ Folder parent,
+ IEnumerable<FileSystemMetadata> fileSystemEntries,
+ IDirectoryService directoryService,
+ bool suppportMultiEditions,
+ string collectionType,
+ bool parseName)
where T : Video, new()
{
var files = new List<FileSystemMetadata>();
@@ -104,8 +111,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
// This is a hack but currently no better way to resolve a sometimes ambiguous situation
if (string.IsNullOrEmpty(collectionType))
{
- if (string.Equals(child.Name, "tvshow.nfo", StringComparison.OrdinalIgnoreCase) ||
- string.Equals(child.Name, "season.nfo", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(child.Name, "tvshow.nfo", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(child.Name, "season.nfo", StringComparison.OrdinalIgnoreCase))
{
return null;
}
@@ -115,11 +122,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
leftOver.Add(child);
}
- else if (IsIgnored(child.Name))
- {
-
- }
- else
+ else if (!IsIgnored(child.Name))
{
files.Add(child);
}
@@ -168,7 +171,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
private static bool IsIgnored(string filename)
{
// Ignore samples
- Match m = Regex.Match(filename,@"\bsample\b",RegexOptions.IgnoreCase);
+ Match m = Regex.Match(filename, @"\bsample\b", RegexOptions.IgnoreCase);
return m.Success;
}
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index dfa1edaff..36adc0b9c 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -152,7 +152,7 @@ namespace Emby.Server.Implementations.Library
/// <returns>System.String.</returns>
private static string GetCacheKey(long internalUserId, Guid itemId)
{
- return internalUserId.ToString(CultureInfo.InvariantCulture) + "-" + itemId.ToString("N");
+ return internalUserId.ToString(CultureInfo.InvariantCulture) + "-" + itemId.ToString("N", CultureInfo.InvariantCulture);
}
public UserItemData GetUserData(User user, BaseItem item)
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
index 1701ced42..c8c8a108d 100644
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ b/Emby.Server.Implementations/Library/UserManager.cs
@@ -266,6 +266,7 @@ namespace Emby.Server.Implementations.Library
builder.Append(c);
}
}
+
return builder.ToString();
}
@@ -286,17 +287,17 @@ namespace Emby.Server.Implementations.Library
if (user != null)
{
var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.Item1;
- updatedUsername = authResult.Item2;
- success = authResult.Item3;
+ authenticationProvider = authResult.authenticationProvider;
+ updatedUsername = authResult.username;
+ success = authResult.success;
}
else
{
// user is null
var authResult = await AuthenticateLocalUser(username, password, hashedPassword, null, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.Item1;
- updatedUsername = authResult.Item2;
- success = authResult.Item3;
+ authenticationProvider = authResult.authenticationProvider;
+ updatedUsername = authResult.username;
+ success = authResult.success;
if (success && authenticationProvider != null && !(authenticationProvider is DefaultAuthenticationProvider))
{
@@ -331,22 +332,25 @@ namespace Emby.Server.Implementations.Library
if (user == null)
{
- throw new SecurityException("Invalid username or password entered.");
+ throw new AuthenticationException("Invalid username or password entered.");
}
if (user.Policy.IsDisabled)
{
- throw new SecurityException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name));
+ throw new AuthenticationException(string.Format(
+ CultureInfo.InvariantCulture,
+ "The {0} account is currently disabled. Please consult with your administrator.",
+ user.Name));
}
if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(remoteEndPoint))
{
- throw new SecurityException("Forbidden.");
+ throw new AuthenticationException("Forbidden.");
}
if (!user.IsParentalScheduleAllowed())
{
- throw new SecurityException("User is not allowed access at this time.");
+ throw new AuthenticationException("User is not allowed access at this time.");
}
// Update LastActivityDate and LastLoginDate, then save
@@ -357,6 +361,7 @@ namespace Emby.Server.Implementations.Library
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
UpdateUser(user);
}
+
UpdateInvalidLoginAttemptCount(user, 0);
}
else
@@ -429,7 +434,7 @@ namespace Emby.Server.Implementations.Library
return providers;
}
- private async Task<Tuple<string, bool>> AuthenticateWithProvider(IAuthenticationProvider provider, string username, string password, User resolvedUser)
+ private async Task<(string username, bool success)> AuthenticateWithProvider(IAuthenticationProvider provider, string username, string password, User resolvedUser)
{
try
{
@@ -444,23 +449,23 @@ namespace Emby.Server.Implementations.Library
authenticationResult = await provider.Authenticate(username, password).ConfigureAwait(false);
}
- if(authenticationResult.Username != username)
+ if (authenticationResult.Username != username)
{
_logger.LogDebug("Authentication provider provided updated username {1}", authenticationResult.Username);
username = authenticationResult.Username;
}
- return new Tuple<string, bool>(username, true);
+ return (username, true);
}
- catch (Exception ex)
+ catch (AuthenticationException ex)
{
- _logger.LogError(ex, "Error authenticating with provider {provider}", provider.Name);
+ _logger.LogError(ex, "Error authenticating with provider {Provider}", provider.Name);
- return new Tuple<string, bool>(username, false);
+ return (username, false);
}
}
- private async Task<Tuple<IAuthenticationProvider, string, bool>> AuthenticateLocalUser(string username, string password, string hashedPassword, User user, string remoteEndPoint)
+ private async Task<(IAuthenticationProvider authenticationProvider, string username, bool success)> AuthenticateLocalUser(string username, string password, string hashedPassword, User user, string remoteEndPoint)
{
string updatedUsername = null;
bool success = false;
@@ -475,15 +480,15 @@ namespace Emby.Server.Implementations.Library
if (password == null)
{
// legacy
- success = string.Equals(GetAuthenticationProvider(user).GetPasswordHash(user), hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
+ success = string.Equals(user.Password, hashedPassword.Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase);
}
else
{
foreach (var provider in GetAuthenticationProviders(user))
{
var providerAuthResult = await AuthenticateWithProvider(provider, username, password, user).ConfigureAwait(false);
- updatedUsername = providerAuthResult.Item1;
- success = providerAuthResult.Item2;
+ updatedUsername = providerAuthResult.username;
+ success = providerAuthResult.success;
if (success)
{
@@ -510,7 +515,7 @@ namespace Emby.Server.Implementations.Library
}
}
- return new Tuple<IAuthenticationProvider, string, bool>(authenticationProvider, username, success);
+ return (authenticationProvider, username, success);
}
private void UpdateInvalidLoginAttemptCount(User user, int newValue)
@@ -593,7 +598,7 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(user));
}
- bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user).Result;
+ bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user);
bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetAuthenticationProvider(user).GetEasyPasswordHash(user));
bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index e9ce682ee..71f16ac3e 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Controller.Channels;
@@ -117,7 +118,7 @@ namespace Emby.Server.Implementations.Library
if (!query.IncludeHidden)
{
- list = list.Where(i => !user.Configuration.MyMediaExcludes.Contains(i.Id.ToString("N"))).ToList();
+ list = list.Where(i => !user.Configuration.MyMediaExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
}
var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
@@ -127,7 +128,7 @@ namespace Emby.Server.Implementations.Library
return list
.OrderBy(i =>
{
- var index = orders.IndexOf(i.Id.ToString("N"));
+ var index = orders.IndexOf(i.Id.ToString("N", CultureInfo.InvariantCulture));
if (index == -1)
{
@@ -136,7 +137,7 @@ namespace Emby.Server.Implementations.Library
{
if (!view.DisplayParentId.Equals(Guid.Empty))
{
- index = orders.IndexOf(view.DisplayParentId.ToString("N"));
+ index = orders.IndexOf(view.DisplayParentId.ToString("N", CultureInfo.InvariantCulture));
}
}
}
@@ -269,7 +270,7 @@ namespace Emby.Server.Implementations.Library
{
parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
.Where(i => i is Folder)
- .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N")))
+ .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
.ToList();
}
diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
index 294348660..b584cc649 100644
--- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -91,7 +92,7 @@ namespace Emby.Server.Implementations.Library.Validators
continue;
}
- _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N"), item.Name, item.GetType().Name);
+ _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name);
_libraryManager.DeleteItem(item, new DeleteOptions
{
diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
index 7899cf01b..d00c6cde1 100644
--- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs
@@ -1,7 +1,7 @@
using System;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -96,7 +96,7 @@ namespace Emby.Server.Implementations.Library.Validators
foreach (var item in deadEntities)
{
- _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N"), item.Name, item.GetType().Name);
+ _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name);
_libraryManager.DeleteItem(item, new DeleteOptions
{
diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
index da4645a11..93ded9e7b 100644
--- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
@@ -76,7 +77,7 @@ namespace Emby.Server.Implementations.Library.Validators
foreach (var item in deadEntities)
{
- _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N"), item.Name, item.GetType().Name);
+ _logger.LogInformation("Deleting dead {2} {0} {1}.", item.Id.ToString("N", CultureInfo.InvariantCulture), item.Name, item.GetType().Name);
_libraryManager.DeleteItem(item, new DeleteOptions
{
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 7b210d231..d7411af50 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -681,7 +681,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
}
- timer.Id = Guid.NewGuid().ToString("N");
+ timer.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
LiveTvProgram programInfo = null;
@@ -713,7 +713,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public async Task<string> CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken)
{
- info.Id = Guid.NewGuid().ToString("N");
+ info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
// populate info.seriesID
var program = GetProgramInfoFromCache(info.ProgramId);
@@ -1059,7 +1059,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var json = _jsonSerializer.SerializeToString(mediaSource);
mediaSource = _jsonSerializer.DeserializeFromString<MediaSourceInfo>(json);
- mediaSource.Id = Guid.NewGuid().ToString("N") + "_" + mediaSource.Id;
+ mediaSource.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture) + "_" + mediaSource.Id;
//if (mediaSource.DateLiveStreamOpened.HasValue && enableStreamSharing)
//{
@@ -2529,7 +2529,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var timer = new TimerInfo
{
ChannelId = channelId,
- Id = (seriesTimer.Id + parent.ExternalId).GetMD5().ToString("N"),
+ Id = (seriesTimer.Id + parent.ExternalId).GetMD5().ToString("N", CultureInfo.InvariantCulture),
StartDate = parent.StartDate,
EndDate = parent.EndDate.Value,
ProgramId = parent.ExternalId,
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index 94225a0aa..88693f22a 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -211,7 +211,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
HasImage = program.Icon != null && !string.IsNullOrEmpty(program.Icon.Source),
OfficialRating = program.Rating != null && !string.IsNullOrEmpty(program.Rating.Value) ? program.Rating.Value : null,
CommunityRating = program.StarRating,
- SeriesId = program.Episode == null ? null : program.Title.GetMD5().ToString("N")
+ SeriesId = program.Episode == null ? null : program.Title.GetMD5().ToString("N", CultureInfo.InvariantCulture)
};
if (string.IsNullOrWhiteSpace(program.ProgramId))
@@ -227,7 +227,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture);
}
- programInfo.ShowId = uniqueString.GetMD5().ToString("N");
+ programInfo.ShowId = uniqueString.GetMD5().ToString("N", CultureInfo.InvariantCulture);
// If we don't have valid episode info, assume it's a unique program, otherwise recordings might be skipped
if (programInfo.IsSeries
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
index 1144c9ab1..e584664c9 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -52,7 +53,7 @@ namespace Emby.Server.Implementations.LiveTv
ExternalId = info.Id,
ChannelId = GetInternalChannelId(service.Name, info.ChannelId),
Status = info.Status,
- SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : GetInternalSeriesTimerId(info.SeriesTimerId).ToString("N"),
+ SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId) ? null : GetInternalSeriesTimerId(info.SeriesTimerId).ToString("N", CultureInfo.InvariantCulture),
PrePaddingSeconds = info.PrePaddingSeconds,
PostPaddingSeconds = info.PostPaddingSeconds,
IsPostPaddingRequired = info.IsPostPaddingRequired,
@@ -69,7 +70,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!string.IsNullOrEmpty(info.ProgramId))
{
- dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N");
+ dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N", CultureInfo.InvariantCulture);
}
if (program != null)
@@ -107,7 +108,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var dto = new SeriesTimerInfoDto
{
- Id = GetInternalSeriesTimerId(info.Id).ToString("N"),
+ Id = GetInternalSeriesTimerId(info.Id).ToString("N", CultureInfo.InvariantCulture),
Overview = info.Overview,
EndDate = info.EndDate,
Name = info.Name,
@@ -139,7 +140,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!string.IsNullOrEmpty(info.ProgramId))
{
- dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N");
+ dto.ProgramId = GetInternalProgramId(info.ProgramId).ToString("N", CultureInfo.InvariantCulture);
}
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray());
@@ -169,7 +170,7 @@ namespace Emby.Server.Implementations.LiveTv
try
{
dto.ParentThumbImageTag = _imageProcessor.GetImageCacheTag(librarySeries, image);
- dto.ParentThumbItemId = librarySeries.Id.ToString("N");
+ dto.ParentThumbItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -185,7 +186,7 @@ namespace Emby.Server.Implementations.LiveTv
{
_imageProcessor.GetImageCacheTag(librarySeries, image)
};
- dto.ParentBackdropItemId = librarySeries.Id.ToString("N");
+ dto.ParentBackdropItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -213,7 +214,7 @@ namespace Emby.Server.Implementations.LiveTv
try
{
dto.ParentPrimaryImageTag = _imageProcessor.GetImageCacheTag(program, image);
- dto.ParentPrimaryImageItemId = program.Id.ToString("N");
+ dto.ParentPrimaryImageItemId = program.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -232,7 +233,7 @@ namespace Emby.Server.Implementations.LiveTv
{
_imageProcessor.GetImageCacheTag(program, image)
};
- dto.ParentBackdropItemId = program.Id.ToString("N");
+ dto.ParentBackdropItemId = program.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -263,7 +264,7 @@ namespace Emby.Server.Implementations.LiveTv
try
{
dto.ParentThumbImageTag = _imageProcessor.GetImageCacheTag(librarySeries, image);
- dto.ParentThumbItemId = librarySeries.Id.ToString("N");
+ dto.ParentThumbItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -279,7 +280,7 @@ namespace Emby.Server.Implementations.LiveTv
{
_imageProcessor.GetImageCacheTag(librarySeries, image)
};
- dto.ParentBackdropItemId = librarySeries.Id.ToString("N");
+ dto.ParentBackdropItemId = librarySeries.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -320,7 +321,7 @@ namespace Emby.Server.Implementations.LiveTv
try
{
dto.ParentPrimaryImageTag = _imageProcessor.GetImageCacheTag(program, image);
- dto.ParentPrimaryImageItemId = program.Id.ToString("N");
+ dto.ParentPrimaryImageItemId = program.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -339,7 +340,7 @@ namespace Emby.Server.Implementations.LiveTv
{
_imageProcessor.GetImageCacheTag(program, image)
};
- dto.ParentBackdropItemId = program.Id.ToString("N");
+ dto.ParentBackdropItemId = program.Id.ToString("N", CultureInfo.InvariantCulture);
}
catch (Exception ex)
{
@@ -407,7 +408,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var name = ServiceName + externalId + InternalVersionNumber;
- return name.ToLowerInvariant().GetMD5().ToString("N");
+ return name.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
public Guid GetInternalSeriesTimerId(string externalId)
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index 9093d9740..1e5198dd6 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -258,7 +259,7 @@ namespace Emby.Server.Implementations.LiveTv
}
info.RequiresClosing = true;
- var idPrefix = service.GetType().FullName.GetMD5().ToString("N") + "_";
+ var idPrefix = service.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture) + "_";
info.LiveStreamId = idPrefix + info.Id;
@@ -820,7 +821,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!string.IsNullOrWhiteSpace(query.SeriesTimerId))
{
var seriesTimers = await GetSeriesTimersInternal(new SeriesTimerQuery { }, cancellationToken).ConfigureAwait(false);
- var seriesTimer = seriesTimers.Items.FirstOrDefault(i => string.Equals(_tvDtoService.GetInternalSeriesTimerId(i.Id).ToString("N"), query.SeriesTimerId, StringComparison.OrdinalIgnoreCase));
+ var seriesTimer = seriesTimers.Items.FirstOrDefault(i => string.Equals(_tvDtoService.GetInternalSeriesTimerId(i.Id).ToString("N", CultureInfo.InvariantCulture), query.SeriesTimerId, StringComparison.OrdinalIgnoreCase));
if (seriesTimer != null)
{
internalQuery.ExternalSeriesId = seriesTimer.SeriesId;
@@ -997,7 +998,7 @@ namespace Emby.Server.Implementations.LiveTv
if (!string.IsNullOrEmpty(timer.SeriesTimerId))
{
program.SeriesTimerId = _tvDtoService.GetInternalSeriesTimerId(timer.SeriesTimerId)
- .ToString("N");
+ .ToString("N", CultureInfo.InvariantCulture);
foundSeriesTimer = true;
}
@@ -1018,7 +1019,7 @@ namespace Emby.Server.Implementations.LiveTv
if (seriesTimer != null)
{
program.SeriesTimerId = _tvDtoService.GetInternalSeriesTimerId(seriesTimer.Id)
- .ToString("N");
+ .ToString("N", CultureInfo.InvariantCulture);
}
}
}
@@ -1472,7 +1473,7 @@ namespace Emby.Server.Implementations.LiveTv
dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId)
? null
- : _tvDtoService.GetInternalSeriesTimerId(info.SeriesTimerId).ToString("N");
+ : _tvDtoService.GetInternalSeriesTimerId(info.SeriesTimerId).ToString("N", CultureInfo.InvariantCulture);
dto.TimerId = string.IsNullOrEmpty(info.Id)
? null
@@ -2027,7 +2028,7 @@ namespace Emby.Server.Implementations.LiveTv
info.StartDate = program.StartDate;
info.Name = program.Name;
info.Overview = program.Overview;
- info.ProgramId = programDto.Id.ToString("N");
+ info.ProgramId = programDto.Id.ToString("N", CultureInfo.InvariantCulture);
info.ExternalProgramId = program.ExternalId;
if (program.EndDate.HasValue)
@@ -2088,7 +2089,7 @@ namespace Emby.Server.Implementations.LiveTv
if (service is ISupportsNewTimerIds supportsNewTimerIds)
{
newTimerId = await supportsNewTimerIds.CreateSeriesTimer(info, cancellationToken).ConfigureAwait(false);
- newTimerId = _tvDtoService.GetInternalSeriesTimerId(newTimerId).ToString("N");
+ newTimerId = _tvDtoService.GetInternalSeriesTimerId(newTimerId).ToString("N", CultureInfo.InvariantCulture);
}
else
{
@@ -2192,7 +2193,7 @@ namespace Emby.Server.Implementations.LiveTv
info.EnabledUsers = _userManager.Users
.Where(IsLiveTvEnabled)
- .Select(i => i.Id.ToString("N"))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
.ToArray();
return info;
@@ -2219,7 +2220,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var parts = id.Split(new[] { '_' }, 2);
- var service = _services.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), parts[0], StringComparison.OrdinalIgnoreCase));
+ var service = _services.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), parts[0], StringComparison.OrdinalIgnoreCase));
if (service == null)
{
@@ -2269,7 +2270,7 @@ namespace Emby.Server.Implementations.LiveTv
if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{
- info.Id = Guid.NewGuid().ToString("N");
+ info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
list.Add(info);
config.TunerHosts = list.ToArray();
}
@@ -2312,7 +2313,7 @@ namespace Emby.Server.Implementations.LiveTv
if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{
- info.Id = Guid.NewGuid().ToString("N");
+ info.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
list.Add(info);
config.ListingProviders = list.ToArray();
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index cd1731de5..52d60c004 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -101,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv
{
var openKeys = new List<string>();
openKeys.Add(item.GetType().Name);
- openKeys.Add(item.Id.ToString("N"));
+ openKeys.Add(item.Id.ToString("N", CultureInfo.InvariantCulture));
openKeys.Add(source.Id ?? string.Empty);
source.OpenToken = string.Join(StreamIdDelimeterString, openKeys.ToArray());
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 761275f8f..db016ec70 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
@@ -11,7 +13,6 @@ using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -20,7 +21,6 @@ using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
@@ -259,7 +259,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
using (var manager = new HdHomerunManager(_socketFactory, Logger))
{
// Legacy HdHomeruns are IPv4 only
- var ipInfo = _networkManager.ParseIpAddress(uri.Host);
+ var ipInfo = IPAddress.Parse(uri.Host);
for (int i = 0; i < model.TunerCount; ++i)
{
@@ -461,7 +461,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
id = "native";
}
- id += "_" + channelId.GetMD5().ToString("N") + "_" + url.GetMD5().ToString("N");
+ id += "_" + channelId.GetMD5().ToString("N", CultureInfo.InvariantCulture) + "_" + url.GetMD5().ToString("N", CultureInfo.InvariantCulture);
var mediaSource = new MediaSourceInfo
{
@@ -675,13 +675,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
// Need a way to set the Receive timeout on the socket otherwise this might never timeout?
try
{
- await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IpEndPointInfo(new IpAddressInfo("255.255.255.255", IpAddressFamily.InterNetwork), 65001), cancellationToken);
+ await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken);
var receiveBuffer = new byte[8192];
while (!cancellationToken.IsCancellationRequested)
{
var response = await udpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
- var deviceIp = response.RemoteEndPoint.IpAddress.Address;
+ var deviceIp = response.RemoteEndPoint.Address.ToString();
// check to make sure we have enough bytes received to be a valid message and make sure the 2nd byte is the discover reply byte
if (response.ReceivedBytes > 13 && response.Buffer[1] == 3)
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 2205c0ecc..6e79441da 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -89,7 +89,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private uint? _lockkey = null;
private int _activeTuner = -1;
private readonly ISocketFactory _socketFactory;
- private IpAddressInfo _remoteIp;
+ private IPAddress _remoteIp;
private ILogger _logger;
private ISocket _currentTcpSocket;
@@ -114,7 +114,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- public async Task<bool> CheckTunerAvailability(IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
+ public async Task<bool> CheckTunerAvailability(IPAddress remoteIp, int tuner, CancellationToken cancellationToken)
{
using (var socket = _socketFactory.CreateTcpSocket(remoteIp, HdHomeRunPort))
{
@@ -122,9 +122,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
- private static async Task<bool> CheckTunerAvailability(ISocket socket, IpAddressInfo remoteIp, int tuner, CancellationToken cancellationToken)
+ private static async Task<bool> CheckTunerAvailability(ISocket socket, IPAddress remoteIp, int tuner, CancellationToken cancellationToken)
{
- var ipEndPoint = new IpEndPointInfo(remoteIp, HdHomeRunPort);
+ var ipEndPoint = new IPEndPoint(remoteIp, HdHomeRunPort);
var lockkeyMsg = CreateGetMessage(tuner, "lockkey");
await socket.SendToAsync(lockkeyMsg, 0, lockkeyMsg.Length, ipEndPoint, cancellationToken);
@@ -137,7 +137,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return string.Equals(returnVal, "none", StringComparison.OrdinalIgnoreCase);
}
- public async Task StartStreaming(IpAddressInfo remoteIp, IPAddress localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken)
+ public async Task StartStreaming(IPAddress remoteIp, IPAddress localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken)
{
_remoteIp = remoteIp;
@@ -154,7 +154,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var lockKeyValue = _lockkey.Value;
- var ipEndPoint = new IpEndPointInfo(_remoteIp, HdHomeRunPort);
+ var ipEndPoint = new IPEndPoint(_remoteIp, HdHomeRunPort);
for (int i = 0; i < numTuners; ++i)
{
@@ -217,7 +217,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
foreach (Tuple<string, string> command in commandList)
{
var channelMsg = CreateSetMessage(_activeTuner, command.Item1, command.Item2, _lockkey);
- await tcpClient.SendToAsync(channelMsg, 0, channelMsg.Length, new IpEndPointInfo(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
+ await tcpClient.SendToAsync(channelMsg, 0, channelMsg.Length, new IPEndPoint(_remoteIp, HdHomeRunPort), cancellationToken).ConfigureAwait(false);
var response = await tcpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
if (!ParseReturnMessage(response.Buffer, response.ReceivedBytes, out string returnVal))
@@ -242,7 +242,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
_logger.LogInformation("HdHomerunManager.ReleaseLockkey {0}", lockKeyValue);
- var ipEndPoint = new IpEndPointInfo(_remoteIp, HdHomeRunPort);
+ var ipEndPoint = new IPEndPoint(_remoteIp, HdHomeRunPort);
var releaseTarget = CreateSetMessage(_activeTuner, "target", "none", lockKeyValue);
await tcpClient.SendToAsync(releaseTarget, 0, releaseTarget.Length, ipEndPoint, CancellationToken.None).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 7f426ea31..ec708cf20 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -25,7 +25,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private readonly int _numTuners;
private readonly INetworkManager _networkManager;
- public HdHomerunUdpStream(MediaSourceInfo mediaSource, TunerHostInfo tunerHostInfo, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, MediaBrowser.Model.Net.ISocketFactory socketFactory, INetworkManager networkManager)
+ public HdHomerunUdpStream(
+ MediaSourceInfo mediaSource,
+ TunerHostInfo tunerHostInfo,
+ string originalStreamId,
+ IHdHomerunChannelCommands channelCommands,
+ int numTuners,
+ IFileSystem fileSystem,
+ IHttpClient httpClient,
+ ILogger logger,
+ IServerApplicationPaths appPaths,
+ IServerApplicationHost appHost,
+ MediaBrowser.Model.Net.ISocketFactory socketFactory,
+ INetworkManager networkManager)
: base(mediaSource, tunerHostInfo, fileSystem, logger, appPaths)
{
_appHost = appHost;
@@ -58,7 +70,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Logger.LogInformation("Opening HDHR UDP Live stream from {host}", uri.Host);
var remoteAddress = IPAddress.Parse(uri.Host);
- var embyRemoteAddress = _networkManager.ParseIpAddress(uri.Host);
IPAddress localAddress = null;
using (var tcpSocket = CreateSocket(remoteAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
@@ -81,7 +92,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
// send url to start streaming
- await hdHomerunManager.StartStreaming(embyRemoteAddress, localAddress, localPort, _channelCommands, _numTuners, openCancellationToken).ConfigureAwait(false);
+ await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, openCancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index ece2cbd54..b4395e2e1 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -42,7 +43,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
MediaSource = mediaSource;
Logger = logger;
EnableStreamSharing = true;
- UniqueId = Guid.NewGuid().ToString("N");
+ UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
if (tuner != null)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index 2d9bec53f..6c5c80827 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private string GetFullChannelIdPrefix(TunerHostInfo info)
{
- return ChannelIdPrefix + info.Url.GetMD5().ToString("N");
+ return ChannelIdPrefix + info.Url.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
protected override async Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
@@ -61,7 +62,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
Name = Name,
SourceType = Type,
Status = LiveTvTunerStatus.Available,
- Id = i.Url.GetMD5().ToString("N"),
+ Id = i.Url.GetMD5().ToString("N", CultureInfo.InvariantCulture),
Url = i.Url
})
.ToList();
@@ -173,7 +174,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
ReadAtNativeFramerate = false,
- Id = channel.Path.GetMD5().ToString("N"),
+ Id = channel.Path.GetMD5().ToString("N", CultureInfo.InvariantCulture),
IsInfiniteStream = true,
IsRemote = isRemote,
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 814031b12..3d2267e75 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -58,6 +58,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
UserAgent = _appHost.ApplicationUserAgent
});
}
+
return Task.FromResult((Stream)File.OpenRead(url));
}
@@ -92,11 +93,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var channel = GetChannelnfo(extInf, tunerHostId, line);
if (string.IsNullOrWhiteSpace(channel.Id))
{
- channel.Id = channelIdPrefix + line.GetMD5().ToString("N");
+ channel.Id = channelIdPrefix + line.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
else
{
- channel.Id = channelIdPrefix + channel.Id.GetMD5().ToString("N");
+ channel.Id = channelIdPrefix + channel.Id.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
channel.Path = line;
diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json
index cb8f4576a..b01abafa1 100644
--- a/Emby.Server.Implementations/Localization/Core/da.json
+++ b/Emby.Server.Implementations/Localization/Core/da.json
@@ -18,11 +18,11 @@
"HeaderAlbumArtists": "Albumkunstnere",
"HeaderCameraUploads": "Kamera Uploads",
"HeaderContinueWatching": "Fortsæt Afspilning",
- "HeaderFavoriteAlbums": "Favoritalbum",
+ "HeaderFavoriteAlbums": "Favoritalbummer",
"HeaderFavoriteArtists": "Favoritkunstnere",
- "HeaderFavoriteEpisodes": "Favorit-afsnit",
- "HeaderFavoriteShows": "Favorit-serier",
- "HeaderFavoriteSongs": "Favorit-sange",
+ "HeaderFavoriteEpisodes": "Favoritepisoder",
+ "HeaderFavoriteShows": "Favoritserier",
+ "HeaderFavoriteSongs": "Favoritsange",
"HeaderLiveTV": "Live TV",
"HeaderNextUp": "Næste",
"HeaderRecordingGroups": "Optagelsesgrupper",
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index c0f988abe..a2fc126a2 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -19,9 +19,9 @@
"HeaderCameraUploads": "Kamera feltöltések",
"HeaderContinueWatching": "Folyamatban lévő filmek",
"HeaderFavoriteAlbums": "Kedvenc Albumok",
- "HeaderFavoriteArtists": "Kedvenc Művészek",
+ "HeaderFavoriteArtists": "Kedvenc Előadók",
"HeaderFavoriteEpisodes": "Kedvenc Epizódok",
- "HeaderFavoriteShows": "Kedvenc Műsorok",
+ "HeaderFavoriteShows": "Kedvenc Sorozatok",
"HeaderFavoriteSongs": "Kedvenc Dalok",
"HeaderLiveTV": "Élő TV",
"HeaderNextUp": "Következik",
diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json
index 92b12409d..e72f1a262 100644
--- a/Emby.Server.Implementations/Localization/Core/pl.json
+++ b/Emby.Server.Implementations/Localization/Core/pl.json
@@ -18,11 +18,11 @@
"HeaderAlbumArtists": "Wykonawcy albumów",
"HeaderCameraUploads": "Przekazane obrazy",
"HeaderContinueWatching": "Kontynuuj odtwarzanie",
- "HeaderFavoriteAlbums": "Albumy ulubione",
- "HeaderFavoriteArtists": "Wykonawcy ulubieni",
- "HeaderFavoriteEpisodes": "Odcinki ulubione",
- "HeaderFavoriteShows": "Seriale ulubione",
- "HeaderFavoriteSongs": "Utwory ulubione",
+ "HeaderFavoriteAlbums": "Ulubione albumy",
+ "HeaderFavoriteArtists": "Ulubieni wykonawcy",
+ "HeaderFavoriteEpisodes": "Ulubione odcinki",
+ "HeaderFavoriteShows": "Ulubione seriale",
+ "HeaderFavoriteSongs": "Ulubione utwory",
"HeaderLiveTV": "Telewizja",
"HeaderNextUp": "Do obejrzenia",
"HeaderRecordingGroups": "Grupy nagrań",
@@ -41,26 +41,26 @@
"Movies": "Filmy",
"Music": "Muzyka",
"MusicVideos": "Teledyski",
- "NameInstallFailed": "Instalacja {0} nieudana.",
+ "NameInstallFailed": "Instalacja {0} nieudana",
"NameSeasonNumber": "Sezon {0}",
- "NameSeasonUnknown": "Sezon nieznany",
+ "NameSeasonUnknown": "Nieznany sezon",
"NewVersionIsAvailable": "Nowa wersja serwera Jellyfin jest dostępna do pobrania.",
"NotificationOptionApplicationUpdateAvailable": "Dostępna aktualizacja aplikacji",
- "NotificationOptionApplicationUpdateInstalled": "Zainstalowano aktualizację aplikacji",
+ "NotificationOptionApplicationUpdateInstalled": "Zaktualizowano aplikację",
"NotificationOptionAudioPlayback": "Rozpoczęto odtwarzanie muzyki",
"NotificationOptionAudioPlaybackStopped": "Odtwarzane dźwięku zatrzymane",
- "NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia mobilnego",
- "NotificationOptionInstallationFailed": "Niepowodzenie instalacji",
+ "NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia przenośnego",
+ "NotificationOptionInstallationFailed": "Nieudana instalacja",
"NotificationOptionNewLibraryContent": "Dodano nową zawartość",
"NotificationOptionPluginError": "Awaria wtyczki",
"NotificationOptionPluginInstalled": "Zainstalowano wtyczkę",
"NotificationOptionPluginUninstalled": "Odinstalowano wtyczkę",
- "NotificationOptionPluginUpdateInstalled": "Zainstalowano aktualizację wtyczki",
+ "NotificationOptionPluginUpdateInstalled": "Zaktualizowano wtyczkę",
"NotificationOptionServerRestartRequired": "Wymagane ponowne uruchomienie serwera",
"NotificationOptionTaskFailed": "Awaria zaplanowanego zadania",
"NotificationOptionUserLockedOut": "Użytkownik zablokowany",
"NotificationOptionVideoPlayback": "Rozpoczęto odtwarzanie wideo",
- "NotificationOptionVideoPlaybackStopped": "Odtwarzanie wideo zatrzymane",
+ "NotificationOptionVideoPlaybackStopped": "Zatrzymano odtwarzanie wideo",
"Photos": "Zdjęcia",
"Playlists": "Listy odtwarzania",
"Plugin": "Wtyczka",
@@ -73,7 +73,7 @@
"ServerNameNeedsToBeRestarted": "{0} wymaga ponownego uruchomienia",
"Shows": "Seriale",
"Songs": "Utwory",
- "StartupEmbyServerIsLoading": "Twa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
+ "StartupEmbyServerIsLoading": "Trwa wczytywanie serwera Jellyfin. Spróbuj ponownie za chwilę.",
"SubtitleDownloadFailureForItem": "Pobieranie napisów dla {0} zakończone niepowodzeniem",
"SubtitleDownloadFailureFromForItem": "Nieudane pobieranie napisów z {0} dla {1}",
"SubtitlesDownloadedForItem": "Pobrano napisy dla {0}",
@@ -91,7 +91,7 @@
"UserPolicyUpdatedWithName": "Zmieniono zasady użytkowania dla {0}",
"UserStartedPlayingItemWithValues": "{0} odtwarza {1} na {2}",
"UserStoppedPlayingItemWithValues": "{0} zakończył odtwarzanie {1} na {2}",
- "ValueHasBeenAddedToLibrary": "{0} został dodany to biblioteki mediów",
+ "ValueHasBeenAddedToLibrary": "{0} został dodany do biblioteki mediów",
"ValueSpecialEpisodeName": "Specjalne - {0}",
"VersionNumber": "Wersja {0}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json
index 5d68416e9..c4ce16dc8 100644
--- a/Emby.Server.Implementations/Localization/Core/pt-BR.json
+++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json
@@ -21,8 +21,8 @@
"HeaderFavoriteAlbums": "Álbuns Favoritos",
"HeaderFavoriteArtists": "Artistas Favoritos",
"HeaderFavoriteEpisodes": "Episódios Favoritos",
- "HeaderFavoriteShows": "Shows Favoritos",
- "HeaderFavoriteSongs": "Musicas Favoritas",
+ "HeaderFavoriteShows": "Séries Favoritas",
+ "HeaderFavoriteSongs": "Músicas Favoritas",
"HeaderLiveTV": "TV ao Vivo",
"HeaderNextUp": "Próximos",
"HeaderRecordingGroups": "Grupos de Gravação",
@@ -32,19 +32,19 @@
"ItemRemovedWithName": "{0} foi removido da biblioteca",
"LabelIpAddressValue": "Endereço IP: {0}",
"LabelRunningTimeValue": "Tempo de execução: {0}",
- "Latest": "Recente",
- "MessageApplicationUpdated": "O servidor Jellyfin foi atualizado",
- "MessageApplicationUpdatedTo": "O Servidor Jellyfin foi atualizado para {0}",
+ "Latest": "Recentes",
+ "MessageApplicationUpdated": "Servidor Jellyfin atualizado",
+ "MessageApplicationUpdatedTo": "Servidor Jellyfin atualizado para {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "A seção {0} da configuração do servidor foi atualizada",
"MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada",
"MixedContent": "Conteúdo misto",
"Movies": "Filmes",
"Music": "Música",
- "MusicVideos": "Vídeos musicais",
+ "MusicVideos": "Clipes",
"NameInstallFailed": "A instalação de {0} falhou",
"NameSeasonNumber": "Temporada {0}",
"NameSeasonUnknown": "Temporada Desconhecida",
- "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para download.",
+ "NewVersionIsAvailable": "Uma nova versão do Servidor Jellyfin está disponível para download.",
"NotificationOptionApplicationUpdateAvailable": "Atualização de aplicativo disponível",
"NotificationOptionApplicationUpdateInstalled": "Atualização de aplicativo instalada",
"NotificationOptionAudioPlayback": "Reprodução de áudio iniciada",
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index 492f48abe..42ffa4e22 100644
--- a/Emby.Server.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -16,14 +16,14 @@ namespace Emby.Server.Implementations.Net
// but that wasn't really the point so kept to YAGNI principal for now, even if the
// interfaces are a bit ugly, specific and make assumptions.
- public ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort)
+ public ISocket CreateTcpSocket(IPAddress remoteAddress, int remotePort)
{
if (remotePort < 0)
{
throw new ArgumentException("remotePort cannot be less than zero.", nameof(remotePort));
}
- var addressFamily = remoteAddress.AddressFamily == IpAddressFamily.InterNetwork
+ var addressFamily = remoteAddress.AddressFamily == AddressFamily.InterNetwork
? AddressFamily.InterNetwork
: AddressFamily.InterNetworkV6;
@@ -40,7 +40,7 @@ namespace Emby.Server.Implementations.Net
try
{
- return new UdpSocket(retVal, new IpEndPointInfo(remoteAddress, remotePort));
+ return new UdpSocket(retVal, new IPEndPoint(remoteAddress, remotePort));
}
catch
{
@@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Net
/// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
/// </summary>
/// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
- public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
+ public ISocket CreateSsdpUdpSocket(IPAddress localIpAddress, int localPort)
{
if (localPort < 0)
{
@@ -115,10 +115,8 @@ namespace Emby.Server.Implementations.Net
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
- var localIp = NetworkManager.ToIPAddress(localIpAddress);
-
- retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIp));
- return new UdpSocket(retVal, localPort, localIp);
+ retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIpAddress));
+ return new UdpSocket(retVal, localPort, localIpAddress);
}
catch
{
diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs
index 6c55085c8..dde4a2a34 100644
--- a/Emby.Server.Implementations/Net/UdpSocket.cs
+++ b/Emby.Server.Implementations/Net/UdpSocket.cs
@@ -3,7 +3,6 @@ using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Server.Implementations.Networking;
using MediaBrowser.Model.Net;
namespace Emby.Server.Implementations.Net
@@ -19,7 +18,7 @@ namespace Emby.Server.Implementations.Net
public Socket Socket => _socket;
- public IpAddressInfo LocalIPAddress { get; }
+ public IPAddress LocalIPAddress { get; }
private readonly SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs()
{
@@ -40,7 +39,7 @@ namespace Emby.Server.Implementations.Net
_socket = socket;
_localPort = localPort;
- LocalIPAddress = NetworkManager.ToIpAddressInfo(ip);
+ LocalIPAddress = ip;
_socket.Bind(new IPEndPoint(ip, _localPort));
@@ -71,7 +70,7 @@ namespace Emby.Server.Implementations.Net
{
Buffer = e.Buffer,
ReceivedBytes = e.BytesTransferred,
- RemoteEndPoint = ToIpEndPointInfo(e.RemoteEndPoint as IPEndPoint),
+ RemoteEndPoint = e.RemoteEndPoint as IPEndPoint,
LocalIPAddress = LocalIPAddress
});
}
@@ -100,12 +99,12 @@ namespace Emby.Server.Implementations.Net
}
}
- public UdpSocket(Socket socket, IpEndPointInfo endPoint)
+ public UdpSocket(Socket socket, IPEndPoint endPoint)
{
if (socket == null) throw new ArgumentNullException(nameof(socket));
_socket = socket;
- _socket.Connect(NetworkManager.ToIPEndPoint(endPoint));
+ _socket.Connect(endPoint);
InitReceiveSocketAsyncEventArgs();
}
@@ -140,7 +139,7 @@ namespace Emby.Server.Implementations.Net
return new SocketReceiveResult
{
ReceivedBytes = receivedBytes,
- RemoteEndPoint = ToIpEndPointInfo((IPEndPoint)remoteEndPoint),
+ RemoteEndPoint = (IPEndPoint)remoteEndPoint,
Buffer = buffer,
LocalIPAddress = LocalIPAddress
};
@@ -191,7 +190,7 @@ namespace Emby.Server.Implementations.Net
return ReceiveAsync(buffer, 0, buffer.Length, cancellationToken);
}
- public Task SendToAsync(byte[] buffer, int offset, int size, IpEndPointInfo endPoint, CancellationToken cancellationToken)
+ public Task SendToAsync(byte[] buffer, int offset, int size, IPEndPoint endPoint, CancellationToken cancellationToken)
{
ThrowIfDisposed();
@@ -227,13 +226,11 @@ namespace Emby.Server.Implementations.Net
return taskCompletion.Task;
}
- public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, IpEndPointInfo endPoint, AsyncCallback callback, object state)
+ public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, IPEndPoint endPoint, AsyncCallback callback, object state)
{
ThrowIfDisposed();
- var ipEndPoint = NetworkManager.ToIPEndPoint(endPoint);
-
- return _socket.BeginSendTo(buffer, offset, size, SocketFlags.None, ipEndPoint, callback, state);
+ return _socket.BeginSendTo(buffer, offset, size, SocketFlags.None, endPoint, callback, state);
}
public int EndSendTo(IAsyncResult result)
@@ -268,15 +265,5 @@ namespace Emby.Server.Implementations.Net
_disposed = true;
}
-
- private static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint)
- {
- if (endpoint == null)
- {
- return null;
- }
-
- return NetworkManager.ToIpEndPointInfo(endpoint);
- }
}
}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs b/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
deleted file mode 100644
index e4e944839..000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Numerics;
-using System.Text;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- /// <summary>
- /// Extension methods to convert <see cref="BigInteger"/>
- /// instances to hexadecimal, octal, and binary strings.
- /// </summary>
- public static class BigIntegerExtensions
- {
- /// <summary>
- /// Converts a <see cref="BigInteger"/> to a binary string.
- /// </summary>
- /// <param name="bigint">A <see cref="BigInteger"/>.</param>
- /// <returns>
- /// A <see cref="string"/> containing a binary
- /// representation of the supplied <see cref="BigInteger"/>.
- /// </returns>
- public static string ToBinaryString(this BigInteger bigint)
- {
- var bytes = bigint.ToByteArray();
- var idx = bytes.Length - 1;
-
- // Create a StringBuilder having appropriate capacity.
- var base2 = new StringBuilder(bytes.Length * 8);
-
- // Convert first byte to binary.
- var binary = Convert.ToString(bytes[idx], 2);
-
- // Ensure leading zero exists if value is positive.
- if (binary[0] != '0' && bigint.Sign == 1)
- {
- base2.Append('0');
- }
-
- // Append binary string to StringBuilder.
- base2.Append(binary);
-
- // Convert remaining bytes adding leading zeros.
- for (idx--; idx >= 0; idx--)
- {
- base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
- }
-
- return base2.ToString();
- }
-
- /// <summary>
- /// Converts a <see cref="BigInteger"/> to a hexadecimal string.
- /// </summary>
- /// <param name="bigint">A <see cref="BigInteger"/>.</param>
- /// <returns>
- /// A <see cref="string"/> containing a hexadecimal
- /// representation of the supplied <see cref="BigInteger"/>.
- /// </returns>
- public static string ToHexadecimalString(this BigInteger bigint)
- {
- return bigint.ToString("X");
- }
-
- /// <summary>
- /// Converts a <see cref="BigInteger"/> to a octal string.
- /// </summary>
- /// <param name="bigint">A <see cref="BigInteger"/>.</param>
- /// <returns>
- /// A <see cref="string"/> containing an octal
- /// representation of the supplied <see cref="BigInteger"/>.
- /// </returns>
- public static string ToOctalString(this BigInteger bigint)
- {
- var bytes = bigint.ToByteArray();
- var idx = bytes.Length - 1;
-
- // Create a StringBuilder having appropriate capacity.
- var base8 = new StringBuilder(((bytes.Length / 3) + 1) * 8);
-
- // Calculate how many bytes are extra when byte array is split
- // into three-byte (24-bit) chunks.
- var extra = bytes.Length % 3;
-
- // If no bytes are extra, use three bytes for first chunk.
- if (extra == 0)
- {
- extra = 3;
- }
-
- // Convert first chunk (24-bits) to integer value.
- int int24 = 0;
- for (; extra != 0; extra--)
- {
- int24 <<= 8;
- int24 += bytes[idx--];
- }
-
- // Convert 24-bit integer to octal without adding leading zeros.
- var octal = Convert.ToString(int24, 8);
-
- // Ensure leading zero exists if value is positive.
- if (octal[0] != '0')
- {
- if (bigint.Sign == 1)
- {
- base8.Append('0');
- }
- }
-
- // Append first converted chunk to StringBuilder.
- base8.Append(octal);
-
- // Convert remaining 24-bit chunks, adding leading zeros.
- for (; idx >= 0; idx -= 3)
- {
- int24 = (bytes[idx] << 16) + (bytes[idx - 1] << 8) + bytes[idx - 2];
- base8.Append(Convert.ToString(int24, 8).PadLeft(8, '0'));
- }
-
- return base8.ToString();
- }
-
- /// <summary>
- ///
- /// Reverse a Positive BigInteger ONLY
- /// Bitwise ~ operator
- ///
- /// Input : FF FF FF FF
- /// Width : 4
- /// Result : 00 00 00 00
- ///
- ///
- /// Input : 00 00 00 00
- /// Width : 4
- /// Result : FF FF FF FF
- ///
- /// Input : FF FF FF FF
- /// Width : 8
- /// Result : FF FF FF FF 00 00 00 00
- ///
- ///
- /// Input : 00 00 00 00
- /// Width : 8
- /// Result : FF FF FF FF FF FF FF FF
- ///
- /// </summary>
- /// <param name="input"></param>
- /// <param name="width"></param>
- /// <returns></returns>
- public static BigInteger PositiveReverse(this BigInteger input, int width)
- {
-
- var result = new List<byte>();
- var bytes = input.ToByteArray();
- var work = new byte[width];
- Array.Copy(bytes, 0, work, 0, bytes.Length - 1); // Length -1 : positive BigInteger
-
- for (int i = 0; i < work.Length; i++)
- {
- result.Add((byte)(~work[i]));
- }
- result.Add(0); // positive BigInteger
- return new BigInteger(result.ToArray());
-
- }
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
deleted file mode 100644
index a0c5f73af..000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Net;
-using System.Numerics;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- public class IPAddressCollection : IEnumerable<IPAddress>, IEnumerator<IPAddress>
- {
-
- private IPNetwork _ipnetwork;
- private BigInteger _enumerator;
-
- internal IPAddressCollection(IPNetwork ipnetwork)
- {
- this._ipnetwork = ipnetwork;
- this._enumerator = -1;
- }
-
-
- #region Count, Array, Enumerator
-
- public BigInteger Count => this._ipnetwork.Total;
-
- public IPAddress this[BigInteger i]
- {
- get
- {
- if (i >= this.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(i));
- }
- byte width = this._ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? (byte)32 : (byte)128;
- var ipn = this._ipnetwork.Subnet(width);
- return ipn[i].Network;
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- IEnumerator<IPAddress> IEnumerable<IPAddress>.GetEnumerator()
- {
- return this;
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this;
- }
-
- #region IEnumerator<IPNetwork> Members
-
- public IPAddress Current => this[this._enumerator];
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- // nothing to dispose
- return;
- }
-
- #endregion
-
- #region IEnumerator Members
-
- object IEnumerator.Current => this.Current;
-
- public bool MoveNext()
- {
- this._enumerator++;
- if (this._enumerator >= this.Count)
- {
- return false;
- }
- return true;
-
- }
-
- public void Reset()
- {
- this._enumerator = -1;
- }
-
- #endregion
-
- #endregion
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
deleted file mode 100644
index d6de61c0c..000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
+++ /dev/null
@@ -1,2008 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Sockets;
-using System.Numerics;
-using System.Text.RegularExpressions;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- /// <summary>
- /// IP Network utility class.
- /// Use IPNetwork.Parse to create instances.
- /// </summary>
- public class IPNetwork : IComparable<IPNetwork>
- {
-
- #region properties
-
- //private uint _network;
- private BigInteger _ipaddress;
- private AddressFamily _family;
- //private uint _netmask;
- //private uint _broadcast;
- //private uint _firstUsable;
- //private uint _lastUsable;
- //private uint _usable;
- private byte _cidr;
-
- #endregion
-
- #region accessors
-
- private BigInteger _network
- {
- get
- {
- var uintNetwork = this._ipaddress & this._netmask;
- return uintNetwork;
- }
- }
-
- /// <summary>
- /// Network address
- /// </summary>
- public IPAddress Network => IPNetwork.ToIPAddress(this._network, this._family);
-
- /// <summary>
- /// Address Family
- /// </summary>
- public AddressFamily AddressFamily => this._family;
-
- private BigInteger _netmask => IPNetwork.ToUint(this._cidr, this._family);
-
- /// <summary>
- /// Netmask
- /// </summary>
- public IPAddress Netmask => IPNetwork.ToIPAddress(this._netmask, this._family);
-
- private BigInteger _broadcast
- {
- get
- {
-
- int width = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16;
- var uintBroadcast = this._network + this._netmask.PositiveReverse(width);
- return uintBroadcast;
- }
- }
-
- /// <summary>
- /// Broadcast address
- /// </summary>
- public IPAddress Broadcast
- {
- get
- {
- if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
- {
- return null;
- }
- return IPNetwork.ToIPAddress(this._broadcast, this._family);
- }
- }
-
- /// <summary>
- /// First usable IP adress in Network
- /// </summary>
- public IPAddress FirstUsable
- {
- get
- {
- var fisrt = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
- ? this._network
- : (this.Usable <= 0) ? this._network : this._network + 1;
- return IPNetwork.ToIPAddress(fisrt, this._family);
- }
- }
-
- /// <summary>
- /// Last usable IP adress in Network
- /// </summary>
- public IPAddress LastUsable
- {
- get
- {
- var last = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
- ? this._broadcast
- : (this.Usable <= 0) ? this._network : this._broadcast - 1;
- return IPNetwork.ToIPAddress(last, this._family);
- }
- }
-
- /// <summary>
- /// Number of usable IP adress in Network
- /// </summary>
- public BigInteger Usable
- {
- get
- {
-
- if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
- {
- return this.Total;
- }
- byte[] mask = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x00 };
- var bmask = new BigInteger(mask);
- var usableIps = (_cidr > 30) ? 0 : ((bmask >> _cidr) - 1);
- return usableIps;
- }
- }
-
- /// <summary>
- /// Number of IP adress in Network
- /// </summary>
- public BigInteger Total
- {
- get
- {
-
- int max = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- var count = BigInteger.Pow(2, (max - _cidr));
- return count;
- }
- }
-
-
- /// <summary>
- /// The CIDR netmask notation
- /// </summary>
- public byte Cidr => this._cidr;
-
- #endregion
-
- #region constructor
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
-
- IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
- {
-
- int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidr > maxCidr)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
-
- this._ipaddress = ipaddress;
- this._family = family;
- this._cidr = cidr;
-
- }
-
- #endregion
-
- #region parsers
-
- /// <summary>
- /// 192.168.168.100 - 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static IPNetwork Parse(string ipaddress, string netmask)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
- return ipnetwork;
- }
-
- /// <summary>
- /// 192.168.168.100/24
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static IPNetwork Parse(string ipaddress, byte cidr)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, ipaddress, cidr, out ipnetwork);
- return ipnetwork;
-
- }
-
- /// <summary>
- /// 192.168.168.100 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static IPNetwork Parse(IPAddress ipaddress, IPAddress netmask)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
- return ipnetwork;
-
- }
-
- /// <summary>
- /// 192.168.0.1/24
- /// 192.168.0.1 255.255.255.0
- ///
- /// Network : 192.168.0.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.0.1
- /// End : 192.168.0.254
- /// Broadcast : 192.168.0.255
- /// </summary>
- /// <param name="network"></param>
- /// <returns></returns>
- public static IPNetwork Parse(string network)
- {
-
- IPNetwork ipnetwork = null;
- IPNetwork.InternalParse(false, network, out ipnetwork);
- return ipnetwork;
-
- }
-
- #endregion
-
- #region TryParse
-
-
-
- /// <summary>
- /// 192.168.168.100 - 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static bool TryParse(string ipaddress, string netmask, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
-
-
- /// <summary>
- /// 192.168.168.100/24
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static bool TryParse(string ipaddress, byte cidr, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, ipaddress, cidr, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
- /// <summary>
- /// 192.168.0.1/24
- /// 192.168.0.1 255.255.255.0
- ///
- /// Network : 192.168.0.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.0.1
- /// End : 192.168.0.254
- /// Broadcast : 192.168.0.255
- /// </summary>
- /// <param name="network"></param>
- /// <param name="ipnetwork"></param>
- /// <returns></returns>
- public static bool TryParse(string network, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, network, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
- /// <summary>
- /// 192.168.0.1/24
- /// 192.168.0.1 255.255.255.0
- ///
- /// Network : 192.168.0.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.0.1
- /// End : 192.168.0.254
- /// Broadcast : 192.168.0.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="netmask"></param>
- /// <param name="ipnetwork"></param>
- /// <returns></returns>
- public static bool TryParse(IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
- {
-
- IPNetwork ipnetwork2 = null;
- IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
- bool parsed = (ipnetwork2 != null);
- ipnetwork = ipnetwork2;
- return parsed;
-
- }
-
-
- #endregion
-
- #region InternalParse
-
- /// <summary>
- /// 192.168.168.100 - 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="netmask"></param>
- /// <returns></returns>
- private static void InternalParse(bool tryParse, string ipaddress, string netmask, out IPNetwork ipnetwork)
- {
-
- if (string.IsNullOrEmpty(ipaddress))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- ipnetwork = null;
- return;
- }
-
- if (string.IsNullOrEmpty(netmask))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- ipnetwork = null;
- return;
- }
-
- IPAddress ip = null;
- bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
- if (ipaddressParsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("ipaddress");
- }
- ipnetwork = null;
- return;
- }
-
- IPAddress mask = null;
- bool netmaskParsed = IPAddress.TryParse(netmask, out mask);
- if (netmaskParsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("netmask");
- }
- ipnetwork = null;
- return;
- }
-
- IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
- }
-
- private static void InternalParse(bool tryParse, string network, out IPNetwork ipnetwork)
- {
-
- if (string.IsNullOrEmpty(network))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(network));
- }
- ipnetwork = null;
- return;
- }
-
- network = Regex.Replace(network, @"[^0-9a-fA-F\.\/\s\:]+", "");
- network = Regex.Replace(network, @"\s{2,}", " ");
- network = network.Trim();
- string[] args = network.Split(new char[] { ' ', '/' });
- byte cidr = 0;
- if (args.Length == 1)
- {
-
- if (IPNetwork.TryGuessCidr(args[0], out cidr))
- {
- IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
- return;
- }
-
- if (tryParse == false)
- {
- throw new ArgumentException("network");
- }
- ipnetwork = null;
- return;
- }
-
- if (byte.TryParse(args[1], out cidr))
- {
- IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
- return;
- }
-
- IPNetwork.InternalParse(tryParse, args[0], args[1], out ipnetwork);
- return;
-
- }
-
-
-
- /// <summary>
- /// 192.168.168.100 255.255.255.0
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="netmask"></param>
- /// <returns></returns>
- private static void InternalParse(bool tryParse, IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
- {
-
- if (ipaddress == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- ipnetwork = null;
- return;
- }
-
- if (netmask == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- ipnetwork = null;
- return;
- }
-
- var uintIpAddress = IPNetwork.ToBigInteger(ipaddress);
- bool parsed = IPNetwork.TryToCidr(netmask, out var cidr2);
- if (parsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("netmask");
- }
- ipnetwork = null;
- return;
- }
- byte cidr = (byte)cidr2;
-
- var ipnet = new IPNetwork(uintIpAddress, ipaddress.AddressFamily, cidr);
- ipnetwork = ipnet;
-
- return;
- }
-
-
-
- /// <summary>
- /// 192.168.168.100/24
- ///
- /// Network : 192.168.168.0
- /// Netmask : 255.255.255.0
- /// Cidr : 24
- /// Start : 192.168.168.1
- /// End : 192.168.168.254
- /// Broadcast : 192.168.168.255
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <param name="cidr"></param>
- /// <returns></returns>
- private static void InternalParse(bool tryParse, string ipaddress, byte cidr, out IPNetwork ipnetwork)
- {
-
- if (string.IsNullOrEmpty(ipaddress))
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- ipnetwork = null;
- return;
- }
-
-
- IPAddress ip = null;
- bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
- if (ipaddressParsed == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("ipaddress");
- }
- ipnetwork = null;
- return;
- }
-
- IPAddress mask = null;
- bool parsedNetmask = IPNetwork.TryToNetmask(cidr, ip.AddressFamily, out mask);
- if (parsedNetmask == false)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("cidr");
- }
- ipnetwork = null;
- return;
- }
-
-
- IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
- }
-
- #endregion
-
- #region converters
-
- #region ToUint
-
- /// <summary>
- /// Convert an ipadress to decimal
- /// 0.0.0.0 -> 0
- /// 0.0.1.0 -> 256
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <returns></returns>
- public static BigInteger ToBigInteger(IPAddress ipaddress)
- {
- IPNetwork.InternalToBigInteger(false, ipaddress, out var uintIpAddress);
- return (BigInteger)uintIpAddress;
-
- }
-
- /// <summary>
- /// Convert an ipadress to decimal
- /// 0.0.0.0 -> 0
- /// 0.0.1.0 -> 256
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <returns></returns>
- public static bool TryToBigInteger(IPAddress ipaddress, out BigInteger? uintIpAddress)
- {
- IPNetwork.InternalToBigInteger(true, ipaddress, out var uintIpAddress2);
- bool parsed = (uintIpAddress2 != null);
- uintIpAddress = uintIpAddress2;
- return parsed;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalToBigInteger(bool tryParse, IPAddress ipaddress, out BigInteger? uintIpAddress)
- {
-
- if (ipaddress == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
- uintIpAddress = null;
- return;
- }
-
- byte[] bytes = ipaddress.GetAddressBytes();
- /// 20180217 lduchosal
- /// code impossible to reach, GetAddressBytes returns either 4 or 16 bytes length addresses
- /// if (bytes.Length != 4 && bytes.Length != 16) {
- /// if (tryParse == false) {
- /// throw new ArgumentException("bytes");
- /// }
- /// uintIpAddress = null;
- /// return;
- /// }
-
- Array.Reverse(bytes);
- var unsigned = new List<byte>(bytes);
- unsigned.Add(0);
- uintIpAddress = new BigInteger(unsigned.ToArray());
- return;
- }
-
-
- /// <summary>
- /// Convert a cidr to BigInteger netmask
- /// </summary>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static BigInteger ToUint(byte cidr, AddressFamily family)
- {
- IPNetwork.InternalToBigInteger(false, cidr, family, out var uintNetmask);
- return (BigInteger)uintNetmask;
- }
-
-
- /// <summary>
- /// Convert a cidr to uint netmask
- /// </summary>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static bool TryToUint(byte cidr, AddressFamily family, out BigInteger? uintNetmask)
- {
- IPNetwork.InternalToBigInteger(true, cidr, family, out var uintNetmask2);
- bool parsed = (uintNetmask2 != null);
- uintNetmask = uintNetmask2;
- return parsed;
- }
-
- /// <summary>
- /// Convert a cidr to uint netmask
- /// </summary>
- /// <param name="cidr"></param>
- /// <returns></returns>
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalToBigInteger(bool tryParse, byte cidr, AddressFamily family, out BigInteger? uintNetmask)
- {
-
- if (family == AddressFamily.InterNetwork && cidr > 32)
- {
- if (tryParse == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- uintNetmask = null;
- return;
- }
-
- if (family == AddressFamily.InterNetworkV6 && cidr > 128)
- {
- if (tryParse == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- uintNetmask = null;
- return;
- }
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- if (tryParse == false)
- {
- throw new NotSupportedException(family.ToString());
- }
- uintNetmask = null;
- return;
- }
-
- if (family == AddressFamily.InterNetwork)
- {
-
- uintNetmask = cidr == 0 ? 0 : 0xffffffff << (32 - cidr);
- return;
- }
-
- var mask = new BigInteger(new byte[] {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0x00
- });
-
- var masked = cidr == 0 ? 0 : mask << (128 - cidr);
- byte[] m = masked.ToByteArray();
- byte[] bmask = new byte[17];
- int copy = m.Length > 16 ? 16 : m.Length;
- Array.Copy(m, 0, bmask, 0, copy);
- uintNetmask = new BigInteger(bmask);
-
-
- }
-
- #endregion
-
- #region ToCidr
-
- /// <summary>
- /// Convert netmask to CIDR
- /// 255.255.255.0 -> 24
- /// 255.255.0.0 -> 16
- /// 255.0.0.0 -> 8
- /// </summary>
- /// <param name="netmask"></param>
- /// <returns></returns>
- private static void InternalToCidr(bool tryParse, BigInteger netmask, AddressFamily family, out byte? cidr)
- {
-
- if (!IPNetwork.InternalValidNetmask(netmask, family))
- {
- if (tryParse == false)
- {
- throw new ArgumentException("netmask");
- }
- cidr = null;
- return;
- }
-
- byte cidr2 = IPNetwork.BitsSet(netmask, family);
- cidr = cidr2;
- return;
-
- }
- /// <summary>
- /// Convert netmask to CIDR
- /// 255.255.255.0 -> 24
- /// 255.255.0.0 -> 16
- /// 255.0.0.0 -> 8
- /// </summary>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static byte ToCidr(IPAddress netmask)
- {
- IPNetwork.InternalToCidr(false, netmask, out var cidr);
- return (byte)cidr;
- }
-
- /// <summary>
- /// Convert netmask to CIDR
- /// 255.255.255.0 -> 24
- /// 255.255.0.0 -> 16
- /// 255.0.0.0 -> 8
- /// </summary>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static bool TryToCidr(IPAddress netmask, out byte? cidr)
- {
- IPNetwork.InternalToCidr(true, netmask, out var cidr2);
- bool parsed = (cidr2 != null);
- cidr = cidr2;
- return parsed;
- }
-
- private static void InternalToCidr(bool tryParse, IPAddress netmask, out byte? cidr)
- {
-
- if (netmask == null)
- {
- if (tryParse == false)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- cidr = null;
- return;
- }
-
- bool parsed = IPNetwork.TryToBigInteger(netmask, out var uintNetmask2);
-
- /// 20180217 lduchosal
- /// impossible to reach code.
- /// if (parsed == false) {
- /// if (tryParse == false) {
- /// throw new ArgumentException("netmask");
- /// }
- /// cidr = null;
- /// return;
- /// }
- var uintNetmask = (BigInteger)uintNetmask2;
-
- IPNetwork.InternalToCidr(tryParse, uintNetmask, netmask.AddressFamily, out var cidr2);
- cidr = cidr2;
-
- return;
-
- }
-
-
- #endregion
-
- #region ToNetmask
-
- /// <summary>
- /// Convert CIDR to netmask
- /// 24 -> 255.255.255.0
- /// 16 -> 255.255.0.0
- /// 8 -> 255.0.0.0
- /// </summary>
- /// <see cref="http://snipplr.com/view/15557/cidr-class-for-ipv4/"/>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static IPAddress ToNetmask(byte cidr, AddressFamily family)
- {
-
- IPAddress netmask = null;
- IPNetwork.InternalToNetmask(false, cidr, family, out netmask);
- return netmask;
- }
-
- /// <summary>
- /// Convert CIDR to netmask
- /// 24 -> 255.255.255.0
- /// 16 -> 255.255.0.0
- /// 8 -> 255.0.0.0
- /// </summary>
- /// <see cref="http://snipplr.com/view/15557/cidr-class-for-ipv4/"/>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static bool TryToNetmask(byte cidr, AddressFamily family, out IPAddress netmask)
- {
-
- IPAddress netmask2 = null;
- IPNetwork.InternalToNetmask(true, cidr, family, out netmask2);
- bool parsed = (netmask2 != null);
- netmask = netmask2;
- return parsed;
- }
-
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalToNetmask(bool tryParse, byte cidr, AddressFamily family, out IPAddress netmask)
- {
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- if (tryParse == false)
- {
- throw new ArgumentException("family");
- }
- netmask = null;
- return;
- }
-
- /// 20180217 lduchosal
- /// impossible to reach code, byte cannot be negative :
- ///
- /// if (cidr < 0) {
- /// if (tryParse == false) {
- /// throw new ArgumentOutOfRangeException("cidr");
- /// }
- /// netmask = null;
- /// return;
- /// }
-
- int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidr > maxCidr)
- {
- if (tryParse == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- netmask = null;
- return;
- }
-
- var mask = IPNetwork.ToUint(cidr, family);
- var netmask2 = IPNetwork.ToIPAddress(mask, family);
- netmask = netmask2;
-
- return;
- }
-
- #endregion
-
- #endregion
-
- #region utils
-
- #region BitsSet
-
- /// <summary>
- /// Count bits set to 1 in netmask
- /// </summary>
- /// <see cref="http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer"/>
- /// <param name="netmask"></param>
- /// <returns></returns>
- private static byte BitsSet(BigInteger netmask, AddressFamily family)
- {
-
- string s = netmask.ToBinaryString();
- return (byte)s.Replace("0", "")
- .ToCharArray()
- .Length;
-
- }
-
-
- /// <summary>
- /// Count bits set to 1 in netmask
- /// </summary>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static uint BitsSet(IPAddress netmask)
- {
- var uintNetmask = IPNetwork.ToBigInteger(netmask);
- uint bits = IPNetwork.BitsSet(uintNetmask, netmask.AddressFamily);
- return bits;
- }
-
- #endregion
-
- #region ValidNetmask
-
- /// <summary>
- /// return true if netmask is a valid netmask
- /// 255.255.255.0, 255.0.0.0, 255.255.240.0, ...
- /// </summary>
- /// <see cref="http://www.actionsnip.com/snippets/tomo_atlacatl/calculate-if-a-netmask-is-valid--as2-"/>
- /// <param name="netmask"></param>
- /// <returns></returns>
- public static bool ValidNetmask(IPAddress netmask)
- {
-
- if (netmask == null)
- {
- throw new ArgumentNullException(nameof(netmask));
- }
- var uintNetmask = IPNetwork.ToBigInteger(netmask);
- bool valid = IPNetwork.InternalValidNetmask(uintNetmask, netmask.AddressFamily);
- return valid;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static bool InternalValidNetmask(BigInteger netmask, AddressFamily family)
- {
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- throw new ArgumentException("family");
- }
-
- var mask = family == AddressFamily.InterNetwork
- ? new BigInteger(0x0ffffffff)
- : new BigInteger(new byte[]{
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0x00
- });
-
- var neg = ((~netmask) & (mask));
- bool isNetmask = ((neg + 1) & neg) == 0;
- return isNetmask;
-
- }
-
- #endregion
-
- #region ToIPAddress
-
- /// <summary>
- /// Transform a uint ipaddress into IPAddress object
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <returns></returns>
- public static IPAddress ToIPAddress(BigInteger ipaddress, AddressFamily family)
- {
-
- int width = family == AddressFamily.InterNetwork ? 4 : 16;
- byte[] bytes = ipaddress.ToByteArray();
- byte[] bytes2 = new byte[width];
- int copy = bytes.Length > width ? width : bytes.Length;
- Array.Copy(bytes, 0, bytes2, 0, copy);
- Array.Reverse(bytes2);
-
- byte[] sized = Resize(bytes2, family);
- var ip = new IPAddress(sized);
- return ip;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static byte[] Resize(byte[] bytes, AddressFamily family)
- {
-
- if (family != AddressFamily.InterNetwork
- && family != AddressFamily.InterNetworkV6)
- {
- throw new ArgumentException("family");
- }
-
- int width = family == AddressFamily.InterNetwork ? 4 : 16;
-
- if (bytes.Length > width)
- {
- throw new ArgumentException("bytes");
- }
-
- byte[] result = new byte[width];
- Array.Copy(bytes, 0, result, 0, bytes.Length);
- return result;
- }
-
- #endregion
-
- #endregion
-
- #region contains
-
- /// <summary>
- /// return true if ipaddress is contained in network
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <returns></returns>
- public bool Contains(IPAddress ipaddress)
- {
-
- if (ipaddress == null)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
-
- if (AddressFamily != ipaddress.AddressFamily)
- {
- return false;
- }
-
- var uintNetwork = _network;
- var uintBroadcast = _broadcast;
- var uintAddress = IPNetwork.ToBigInteger(ipaddress);
-
- bool contains = (uintAddress >= uintNetwork
- && uintAddress <= uintBroadcast);
-
- return contains;
-
- }
-
- /// <summary>
- /// return true is network2 is fully contained in network
- /// </summary>
- /// <param name="network2"></param>
- /// <returns></returns>
- public bool Contains(IPNetwork network2)
- {
-
- if (network2 == null)
- {
- throw new ArgumentNullException(nameof(network2));
- }
-
- var uintNetwork = _network;
- var uintBroadcast = _broadcast;
-
- var uintFirst = network2._network;
- var uintLast = network2._broadcast;
-
- bool contains = (uintFirst >= uintNetwork
- && uintLast <= uintBroadcast);
-
- return contains;
- }
-
- #endregion
-
- #region overlap
-
- /// <summary>
- /// return true is network2 overlap network
- /// </summary>
- /// <param name="network2"></param>
- /// <returns></returns>
- public bool Overlap(IPNetwork network2)
- {
-
- if (network2 == null)
- {
- throw new ArgumentNullException(nameof(network2));
- }
-
- var uintNetwork = _network;
- var uintBroadcast = _broadcast;
-
- var uintFirst = network2._network;
- var uintLast = network2._broadcast;
-
- bool overlap =
- (uintFirst >= uintNetwork && uintFirst <= uintBroadcast)
- || (uintLast >= uintNetwork && uintLast <= uintBroadcast)
- || (uintFirst <= uintNetwork && uintLast >= uintBroadcast)
- || (uintFirst >= uintNetwork && uintLast <= uintBroadcast);
-
- return overlap;
- }
-
- #endregion
-
- #region ToString
-
- public override string ToString()
- {
- return string.Format("{0}/{1}", this.Network, this.Cidr);
- }
-
- #endregion
-
- #region IANA block
-
- private static readonly Lazy<IPNetwork> _iana_ablock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("10.0.0.0/8"));
- private static readonly Lazy<IPNetwork> _iana_bblock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("172.16.0.0/12"));
- private static readonly Lazy<IPNetwork> _iana_cblock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("192.168.0.0/16"));
-
- /// <summary>
- /// 10.0.0.0/8
- /// </summary>
- /// <returns></returns>
- public static IPNetwork IANA_ABLK_RESERVED1 => _iana_ablock_reserved.Value;
-
- /// <summary>
- /// 172.12.0.0/12
- /// </summary>
- /// <returns></returns>
- public static IPNetwork IANA_BBLK_RESERVED1 => _iana_bblock_reserved.Value;
-
- /// <summary>
- /// 192.168.0.0/16
- /// </summary>
- /// <returns></returns>
- public static IPNetwork IANA_CBLK_RESERVED1 => _iana_cblock_reserved.Value;
-
- /// <summary>
- /// return true if ipaddress is contained in
- /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
- /// </summary>
- /// <param name="ipaddress"></param>
- /// <returns></returns>
- public static bool IsIANAReserved(IPAddress ipaddress)
- {
-
- if (ipaddress == null)
- {
- throw new ArgumentNullException(nameof(ipaddress));
- }
-
- return IPNetwork.IANA_ABLK_RESERVED1.Contains(ipaddress)
- || IPNetwork.IANA_BBLK_RESERVED1.Contains(ipaddress)
- || IPNetwork.IANA_CBLK_RESERVED1.Contains(ipaddress);
- }
-
- /// <summary>
- /// return true if ipnetwork is contained in
- /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
- /// </summary>
- /// <returns></returns>
- public bool IsIANAReserved()
- {
- return IPNetwork.IANA_ABLK_RESERVED1.Contains(this)
- || IPNetwork.IANA_BBLK_RESERVED1.Contains(this)
- || IPNetwork.IANA_CBLK_RESERVED1.Contains(this);
- }
-
- #endregion
-
- #region Subnet
-
- /// <summary>
- /// Subnet a network into multiple nets of cidr mask
- /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
- /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
- /// </summary>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public IPNetworkCollection Subnet(byte cidr)
- {
- IPNetworkCollection ipnetworkCollection = null;
- IPNetwork.InternalSubnet(false, this, cidr, out ipnetworkCollection);
- return ipnetworkCollection;
- }
-
- /// <summary>
- /// Subnet a network into multiple nets of cidr mask
- /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
- /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
- /// </summary>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public bool TrySubnet(byte cidr, out IPNetworkCollection ipnetworkCollection)
- {
- IPNetworkCollection inc = null;
- IPNetwork.InternalSubnet(true, this, cidr, out inc);
- if (inc == null)
- {
- ipnetworkCollection = null;
- return false;
- }
-
- ipnetworkCollection = inc;
- return true;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalSubnet(bool trySubnet, IPNetwork network, byte cidr, out IPNetworkCollection ipnetworkCollection)
- {
-
- if (network == null)
- {
- if (trySubnet == false)
- {
- throw new ArgumentNullException(nameof(network));
- }
- ipnetworkCollection = null;
- return;
- }
-
- int maxCidr = network._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidr > maxCidr)
- {
- if (trySubnet == false)
- {
- throw new ArgumentOutOfRangeException(nameof(cidr));
- }
- ipnetworkCollection = null;
- return;
- }
-
- if (cidr < network.Cidr)
- {
- if (trySubnet == false)
- {
- throw new ArgumentException("cidr");
- }
- ipnetworkCollection = null;
- return;
- }
-
- ipnetworkCollection = new IPNetworkCollection(network, cidr);
- return;
- }
-
-
-
- #endregion
-
- #region Supernet
-
- /// <summary>
- /// Supernet two consecutive cidr equal subnet into a single one
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
- /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
- /// </summary>
- /// <param name="network2"></param>
- /// <returns></returns>
- public IPNetwork Supernet(IPNetwork network2)
- {
- IPNetwork supernet = null;
- IPNetwork.InternalSupernet(false, this, network2, out supernet);
- return supernet;
- }
-
- /// <summary>
- /// Try to supernet two consecutive cidr equal subnet into a single one
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
- /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
- /// </summary>
- /// <param name="network2"></param>
- /// <returns></returns>
- public bool TrySupernet(IPNetwork network2, out IPNetwork supernet)
- {
-
- IPNetwork outSupernet = null;
- IPNetwork.InternalSupernet(true, this, network2, out outSupernet);
- bool parsed = (outSupernet != null);
- supernet = outSupernet;
- return parsed;
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static void InternalSupernet(bool trySupernet, IPNetwork network1, IPNetwork network2, out IPNetwork supernet)
- {
-
- if (network1 == null)
- {
- if (trySupernet == false)
- {
- throw new ArgumentNullException(nameof(network1));
- }
- supernet = null;
- return;
- }
-
- if (network2 == null)
- {
- if (trySupernet == false)
- {
- throw new ArgumentNullException(nameof(network2));
- }
- supernet = null;
- return;
- }
-
-
- if (network1.Contains(network2))
- {
- supernet = new IPNetwork(network1._network, network1._family, network1.Cidr);
- return;
- }
-
- if (network2.Contains(network1))
- {
- supernet = new IPNetwork(network2._network, network2._family, network2.Cidr);
- return;
- }
-
- if (network1._cidr != network2._cidr)
- {
- if (trySupernet == false)
- {
- throw new ArgumentException("cidr");
- }
- supernet = null;
- return;
- }
-
- var first = (network1._network < network2._network) ? network1 : network2;
- var last = (network1._network > network2._network) ? network1 : network2;
-
- /// Starting from here :
- /// network1 and network2 have the same cidr,
- /// network1 does not contain network2,
- /// network2 does not contain network1,
- /// first is the lower subnet
- /// last is the higher subnet
-
-
- if ((first._broadcast + 1) != last._network)
- {
- if (trySupernet == false)
- {
- throw new ArgumentOutOfRangeException(nameof(trySupernet), "TrySupernet was false while the first and last networks are not adjacent.");
- }
- supernet = null;
- return;
- }
-
- var uintSupernet = first._network;
- byte cidrSupernet = (byte)(first._cidr - 1);
-
- var networkSupernet = new IPNetwork(uintSupernet, first._family, cidrSupernet);
- if (networkSupernet._network != first._network)
- {
- if (trySupernet == false)
- {
- throw new ArgumentException("network");
- }
- supernet = null;
- return;
- }
- supernet = networkSupernet;
- return;
- }
-
- #endregion
-
- #region GetHashCode
-
- public override int GetHashCode()
- {
- return string.Format("{0}|{1}|{2}",
- this._ipaddress.GetHashCode(),
- this._network.GetHashCode(),
- this._cidr.GetHashCode()).GetHashCode();
- }
-
- #endregion
-
- #region SupernetArray
-
- /// <summary>
- /// Supernet a list of subnet
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
- /// </summary>
- /// <param name="ipnetworks">The IP networks</param>
- /// <returns></returns>
- public static IPNetwork[] Supernet(IPNetwork[] ipnetworks)
- {
- InternalSupernet(false, ipnetworks, out var supernet);
- return supernet;
- }
-
- /// <summary>
- /// Supernet a list of subnet
- /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
- /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
- /// </summary>
- /// <param name="ipnetworks"></param>
- /// <param name="supernet"></param>
- /// <returns></returns>
- public static bool TrySupernet(IPNetwork[] ipnetworks, out IPNetwork[] supernet)
- {
- bool supernetted = InternalSupernet(true, ipnetworks, out supernet);
- return supernetted;
-
- }
-
-#if TRAVISCI
- public
-#else
- internal
-#endif
- static bool InternalSupernet(bool trySupernet, IPNetwork[] ipnetworks, out IPNetwork[] supernet)
- {
-
- if (ipnetworks == null)
- {
- if (trySupernet == false)
- {
- throw new ArgumentNullException(nameof(ipnetworks));
- }
- supernet = null;
- return false;
- }
-
- if (ipnetworks.Length <= 0)
- {
- supernet = new IPNetwork[0];
- return true;
- }
-
- var supernetted = new List<IPNetwork>();
- var ipns = IPNetwork.Array2List(ipnetworks);
- var current = IPNetwork.List2Stack(ipns);
- int previousCount = 0;
- int currentCount = current.Count;
-
- while (previousCount != currentCount)
- {
-
- supernetted.Clear();
- while (current.Count > 1)
- {
- var ipn1 = current.Pop();
- var ipn2 = current.Peek();
-
- IPNetwork outNetwork = null;
- bool success = ipn1.TrySupernet(ipn2, out outNetwork);
- if (success)
- {
- current.Pop();
- current.Push(outNetwork);
- }
- else
- {
- supernetted.Add(ipn1);
- }
- }
- if (current.Count == 1)
- {
- supernetted.Add(current.Pop());
- }
-
- previousCount = currentCount;
- currentCount = supernetted.Count;
- current = IPNetwork.List2Stack(supernetted);
-
- }
- supernet = supernetted.ToArray();
- return true;
- }
-
- private static Stack<IPNetwork> List2Stack(List<IPNetwork> list)
- {
- var stack = new Stack<IPNetwork>();
- list.ForEach(new Action<IPNetwork>(
- delegate (IPNetwork ipn)
- {
- stack.Push(ipn);
- }
- ));
- return stack;
- }
-
- private static List<IPNetwork> Array2List(IPNetwork[] array)
- {
- var ipns = new List<IPNetwork>();
- ipns.AddRange(array);
- IPNetwork.RemoveNull(ipns);
- ipns.Sort(new Comparison<IPNetwork>(
- delegate (IPNetwork ipn1, IPNetwork ipn2)
- {
- int networkCompare = ipn1._network.CompareTo(ipn2._network);
- if (networkCompare == 0)
- {
- int cidrCompare = ipn1._cidr.CompareTo(ipn2._cidr);
- return cidrCompare;
- }
- return networkCompare;
- }
- ));
- ipns.Reverse();
-
- return ipns;
- }
-
- private static void RemoveNull(List<IPNetwork> ipns)
- {
- ipns.RemoveAll(new Predicate<IPNetwork>(
- delegate (IPNetwork ipn)
- {
- if (ipn == null)
- {
- return true;
- }
- return false;
- }
- ));
-
- }
-
- #endregion
-
- #region WideSubnet
-
- public static IPNetwork WideSubnet(string start, string end)
- {
-
- if (string.IsNullOrEmpty(start))
- {
- throw new ArgumentNullException(nameof(start));
- }
-
- if (string.IsNullOrEmpty(end))
- {
- throw new ArgumentNullException(nameof(end));
- }
-
- if (!IPAddress.TryParse(start, out var startIP))
- {
- throw new ArgumentException("start");
- }
-
- if (!IPAddress.TryParse(end, out var endIP))
- {
- throw new ArgumentException("end");
- }
-
- if (startIP.AddressFamily != endIP.AddressFamily)
- {
- throw new NotSupportedException("MixedAddressFamily");
- }
-
- var ipnetwork = new IPNetwork(0, startIP.AddressFamily, 0);
- for (byte cidr = 32; cidr >= 0; cidr--)
- {
- var wideSubnet = IPNetwork.Parse(start, cidr);
- if (wideSubnet.Contains(endIP))
- {
- ipnetwork = wideSubnet;
- break;
- }
- }
- return ipnetwork;
-
- }
-
- public static bool TryWideSubnet(IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
- {
- IPNetwork ipn = null;
- IPNetwork.InternalWideSubnet(true, ipnetworks, out ipn);
- if (ipn == null)
- {
- ipnetwork = null;
- return false;
- }
- ipnetwork = ipn;
- return true;
- }
-
- public static IPNetwork WideSubnet(IPNetwork[] ipnetworks)
- {
- IPNetwork ipn = null;
- IPNetwork.InternalWideSubnet(false, ipnetworks, out ipn);
- return ipn;
- }
-
- internal static void InternalWideSubnet(bool tryWide, IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
- {
-
- if (ipnetworks == null)
- {
- if (tryWide == false)
- {
- throw new ArgumentNullException(nameof(ipnetworks));
- }
- ipnetwork = null;
- return;
- }
-
-
- IPNetwork[] nnin = Array.FindAll(ipnetworks, new Predicate<IPNetwork>(
- delegate (IPNetwork ipnet)
- {
- return ipnet != null;
- }
- ));
-
- if (nnin.Length <= 0)
- {
- if (tryWide == false)
- {
- throw new ArgumentException("ipnetworks");
- }
- ipnetwork = null;
- return;
- }
-
- if (nnin.Length == 1)
- {
- var ipn0 = nnin[0];
- ipnetwork = ipn0;
- return;
- }
-
- Array.Sort(nnin);
- var nnin0 = nnin[0];
- var uintNnin0 = nnin0._ipaddress;
-
- var nninX = nnin[nnin.Length - 1];
- var ipaddressX = nninX.Broadcast;
-
- var family = ipnetworks[0]._family;
- foreach (var ipnx in ipnetworks)
- {
- if (ipnx._family != family)
- {
- throw new ArgumentException("MixedAddressFamily");
- }
- }
-
- var ipn = new IPNetwork(0, family, 0);
- for (byte cidr = nnin0._cidr; cidr >= 0; cidr--)
- {
- var wideSubnet = new IPNetwork(uintNnin0, family, cidr);
- if (wideSubnet.Contains(ipaddressX))
- {
- ipn = wideSubnet;
- break;
- }
- }
-
- ipnetwork = ipn;
- return;
- }
-
- #endregion
-
- #region Print
-
- /// <summary>
- /// Print an ipnetwork in a clear representation string
- /// </summary>
- /// <returns></returns>
- public string Print()
- {
-
- var sw = new StringWriter();
-
- sw.WriteLine("IPNetwork : {0}", ToString());
- sw.WriteLine("Network : {0}", Network);
- sw.WriteLine("Netmask : {0}", Netmask);
- sw.WriteLine("Cidr : {0}", Cidr);
- sw.WriteLine("Broadcast : {0}", Broadcast);
- sw.WriteLine("FirstUsable : {0}", FirstUsable);
- sw.WriteLine("LastUsable : {0}", LastUsable);
- sw.WriteLine("Usable : {0}", Usable);
-
- return sw.ToString();
- }
-
- #endregion
-
- #region TryGuessCidr
-
- /// <summary>
- ///
- /// Class Leading bits Default netmask
- /// A (CIDR /8) 00 255.0.0.0
- /// A (CIDR /8) 01 255.0.0.0
- /// B (CIDR /16) 10 255.255.0.0
- /// C (CIDR /24) 11 255.255.255.0
- ///
- /// </summary>
- /// <param name="ip"></param>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static bool TryGuessCidr(string ip, out byte cidr)
- {
-
- IPAddress ipaddress = null;
- bool parsed = IPAddress.TryParse(string.Format("{0}", ip), out ipaddress);
- if (parsed == false)
- {
- cidr = 0;
- return false;
- }
-
- if (ipaddress.AddressFamily == AddressFamily.InterNetworkV6)
- {
- cidr = 64;
- return true;
- }
- var uintIPAddress = IPNetwork.ToBigInteger(ipaddress);
- uintIPAddress = uintIPAddress >> 29;
- if (uintIPAddress <= 3)
- {
- cidr = 8;
- return true;
- }
- else if (uintIPAddress <= 5)
- {
- cidr = 16;
- return true;
- }
- else if (uintIPAddress <= 6)
- {
- cidr = 24;
- return true;
- }
-
- cidr = 0;
- return false;
-
- }
-
- /// <summary>
- /// Try to parse cidr. Have to be >= 0 and <= 32 or 128
- /// </summary>
- /// <param name="sidr"></param>
- /// <param name="cidr"></param>
- /// <returns></returns>
- public static bool TryParseCidr(string sidr, AddressFamily family, out byte? cidr)
- {
-
- byte b = 0;
- if (!byte.TryParse(sidr, out b))
- {
- cidr = null;
- return false;
- }
-
- IPAddress netmask = null;
- if (!IPNetwork.TryToNetmask(b, family, out netmask))
- {
- cidr = null;
- return false;
- }
-
- cidr = b;
- return true;
- }
-
- #endregion
-
- #region ListIPAddress
-
- public IPAddressCollection ListIPAddress()
- {
- return new IPAddressCollection(this);
- }
-
- #endregion
-
- /**
- * Need a better way to do it
- *
-#region TrySubstractNetwork
-
- public static bool TrySubstractNetwork(IPNetwork[] ipnetworks, IPNetwork substract, out IEnumerable<IPNetwork> result) {
-
- if (ipnetworks == null) {
- result = null;
- return false;
- }
- if (ipnetworks.Length <= 0) {
- result = null;
- return false;
- }
- if (substract == null) {
- result = null;
- return false;
- }
- var results = new List<IPNetwork>();
- foreach (var ipn in ipnetworks) {
- if (!Overlap(ipn, substract)) {
- results.Add(ipn);
- continue;
- }
-
- var collection = ipn.Subnet(substract.Cidr);
- var rtemp = new List<IPNetwork>();
- foreach(var subnet in collection) {
- if (subnet != substract) {
- rtemp.Add(subnet);
- }
- }
- var supernets = Supernet(rtemp.ToArray());
- results.AddRange(supernets);
- }
- result = results;
- return true;
- }
-#endregion
- * **/
-
- #region IComparable<IPNetwork> Members
-
- public static int Compare(IPNetwork left, IPNetwork right)
- {
- // two null IPNetworks are equal
- if (ReferenceEquals(left, null) && ReferenceEquals(right, null)) return 0;
-
- // two same IPNetworks are equal
- if (ReferenceEquals(left, right)) return 0;
-
- // null is always sorted first
- if (ReferenceEquals(left, null)) return -1;
- if (ReferenceEquals(right, null)) return 1;
-
- // first test the network
- var result = left._network.CompareTo(right._network);
- if (result != 0) return result;
-
- // then test the cidr
- result = left._cidr.CompareTo(right._cidr);
- return result;
- }
-
- public int CompareTo(IPNetwork other)
- {
- return Compare(this, other);
- }
-
- public int CompareTo(object obj)
- {
- // null is at less
- if (obj == null) return 1;
-
- // convert to a proper Cidr object
- var other = obj as IPNetwork;
-
- // type problem if null
- if (other == null)
- {
- throw new ArgumentException(
- "The supplied parameter is an invalid type. Please supply an IPNetwork type.",
- nameof(obj));
- }
-
- // perform the comparision
- return CompareTo(other);
- }
-
- #endregion
-
- #region IEquatable<IPNetwork> Members
-
- public static bool Equals(IPNetwork left, IPNetwork right)
- {
- return Compare(left, right) == 0;
- }
-
- public bool Equals(IPNetwork other)
- {
- return Equals(this, other);
- }
-
- public override bool Equals(object obj)
- {
- return Equals(this, obj as IPNetwork);
- }
-
- #endregion
-
- #region Operators
-
- public static bool operator ==(IPNetwork left, IPNetwork right)
- {
- return Equals(left, right);
- }
-
- public static bool operator !=(IPNetwork left, IPNetwork right)
- {
- return !Equals(left, right);
- }
-
- public static bool operator <(IPNetwork left, IPNetwork right)
- {
- return Compare(left, right) < 0;
- }
-
- public static bool operator >(IPNetwork left, IPNetwork right)
- {
- return Compare(left, right) > 0;
- }
-
- #endregion
-
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
deleted file mode 100644
index 4cda421e5..000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Numerics;
-
-namespace Emby.Server.Implementations.Networking.IPNetwork
-{
- public class IPNetworkCollection : IEnumerable<IPNetwork>, IEnumerator<IPNetwork>
- {
-
- private BigInteger _enumerator;
- private byte _cidrSubnet;
- private IPNetwork _ipnetwork;
-
- private byte _cidr => this._ipnetwork.Cidr;
-
- private BigInteger _broadcast => IPNetwork.ToBigInteger(this._ipnetwork.Broadcast);
-
- private BigInteger _lastUsable => IPNetwork.ToBigInteger(this._ipnetwork.LastUsable);
- private BigInteger _network => IPNetwork.ToBigInteger(this._ipnetwork.Network);
-#if TRAVISCI
- public
-#else
- internal
-#endif
- IPNetworkCollection(IPNetwork ipnetwork, byte cidrSubnet)
- {
-
- int maxCidr = ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
- if (cidrSubnet > maxCidr)
- {
- throw new ArgumentOutOfRangeException(nameof(cidrSubnet));
- }
-
- if (cidrSubnet < ipnetwork.Cidr)
- {
- throw new ArgumentException("cidr");
- }
-
- this._cidrSubnet = cidrSubnet;
- this._ipnetwork = ipnetwork;
- this._enumerator = -1;
- }
-
- #region Count, Array, Enumerator
-
- public BigInteger Count
- {
- get
- {
- var count = BigInteger.Pow(2, this._cidrSubnet - this._cidr);
- return count;
- }
- }
-
- public IPNetwork this[BigInteger i]
- {
- get
- {
- if (i >= this.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(i));
- }
-
- var last = this._ipnetwork.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6
- ? this._lastUsable : this._broadcast;
- var increment = (last - this._network) / this.Count;
- var uintNetwork = this._network + ((increment + 1) * i);
- var ipn = new IPNetwork(uintNetwork, this._ipnetwork.AddressFamily, this._cidrSubnet);
- return ipn;
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- IEnumerator<IPNetwork> IEnumerable<IPNetwork>.GetEnumerator()
- {
- return this;
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this;
- }
-
- #region IEnumerator<IPNetwork> Members
-
- public IPNetwork Current => this[this._enumerator];
-
- #endregion
-
- #region IDisposable Members
-
- public void Dispose()
- {
- // nothing to dispose
- return;
- }
-
- #endregion
-
- #region IEnumerator Members
-
- object IEnumerator.Current => this.Current;
-
- public bool MoveNext()
- {
- this._enumerator++;
- if (this._enumerator >= this.Count)
- {
- return false;
- }
- return true;
-
- }
-
- public void Reset()
- {
- this._enumerator = -1;
- }
-
- #endregion
-
- #endregion
-
- }
-}
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt b/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
deleted file mode 100644
index 45d7392ac..000000000
--- a/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2015, lduchosal
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index c102f9eb5..7d85a0666 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -9,55 +9,38 @@ using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
using Microsoft.Extensions.Logging;
-using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
namespace Emby.Server.Implementations.Networking
{
public class NetworkManager : INetworkManager
{
- protected ILogger Logger { get; private set; }
+ private readonly ILogger _logger;
- public event EventHandler NetworkChanged;
- public Func<string[]> LocalSubnetsFn { get; set; }
+ private IPAddress[] _localIpAddresses;
+ private readonly object _localIpAddressSyncLock = new object();
- public NetworkManager(ILoggerFactory loggerFactory)
+ public NetworkManager(ILogger<NetworkManager> logger)
{
- Logger = loggerFactory.CreateLogger(nameof(NetworkManager));
-
- // In FreeBSD these events cause a crash
- if (OperatingSystem.Id != OperatingSystemId.BSD)
- {
- try
- {
- NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error binding to NetworkAddressChanged event");
- }
+ _logger = logger;
- try
- {
- NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error binding to NetworkChange_NetworkAvailabilityChanged event");
- }
- }
+ NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged;
+ NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
}
- private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
+ public Func<string[]> LocalSubnetsFn { get; set; }
+
+ public event EventHandler NetworkChanged;
+
+ private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
- Logger.LogDebug("NetworkAvailabilityChanged");
+ _logger.LogDebug("NetworkAvailabilityChanged");
OnNetworkChanged();
}
- private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
+ private void OnNetworkAddressChanged(object sender, EventArgs e)
{
- Logger.LogDebug("NetworkAddressChanged");
+ _logger.LogDebug("NetworkAddressChanged");
OnNetworkChanged();
}
@@ -68,39 +51,35 @@ namespace Emby.Server.Implementations.Networking
_localIpAddresses = null;
_macAddresses = null;
}
+
if (NetworkChanged != null)
{
NetworkChanged(this, EventArgs.Empty);
}
}
- private IpAddressInfo[] _localIpAddresses;
- private readonly object _localIpAddressSyncLock = new object();
-
- public IpAddressInfo[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
+ public IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
{
lock (_localIpAddressSyncLock)
{
if (_localIpAddresses == null)
{
- var addresses = GetLocalIpAddressesInternal(ignoreVirtualInterface).Result.Select(ToIpAddressInfo).ToArray();
+ var addresses = GetLocalIpAddressesInternal(ignoreVirtualInterface).ToArray();
_localIpAddresses = addresses;
-
- return addresses;
}
+
return _localIpAddresses;
}
}
- private async Task<List<IPAddress>> GetLocalIpAddressesInternal(bool ignoreVirtualInterface)
+ private List<IPAddress> GetLocalIpAddressesInternal(bool ignoreVirtualInterface)
{
- var list = GetIPsDefault(ignoreVirtualInterface)
- .ToList();
+ var list = GetIPsDefault(ignoreVirtualInterface).ToList();
if (list.Count == 0)
{
- list.AddRange(await GetLocalIpAddressesFallback().ConfigureAwait(false));
+ list = GetLocalIpAddressesFallback().GetAwaiter().GetResult().ToList();
}
var listClone = list.ToList();
@@ -116,9 +95,8 @@ namespace Emby.Server.Implementations.Networking
private static bool FilterIpAddress(IPAddress address)
{
- var addressString = address.ToString();
-
- if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
+ if (address.IsIPv6LinkLocal
+ || address.ToString().StartsWith("169.", StringComparison.OrdinalIgnoreCase))
{
return false;
}
@@ -279,7 +257,7 @@ namespace Emby.Server.Implementations.Networking
if (normalizedSubnet.IndexOf('/') != -1)
{
- var ipnetwork = IPNetwork.IPNetwork.Parse(normalizedSubnet);
+ var ipnetwork = IPNetwork.Parse(normalizedSubnet);
if (ipnetwork.Contains(address))
{
return true;
@@ -351,13 +329,13 @@ namespace Emby.Server.Implementations.Networking
try
{
var host = uri.DnsSafeHost;
- Logger.LogDebug("Resolving host {0}", host);
+ _logger.LogDebug("Resolving host {0}", host);
address = GetIpAddresses(host).Result.FirstOrDefault();
if (address != null)
{
- Logger.LogDebug("{0} resolved to {1}", host, address);
+ _logger.LogDebug("{0} resolved to {1}", host, address);
return IsInLocalNetworkInternal(address.ToString(), false);
}
@@ -368,7 +346,7 @@ namespace Emby.Server.Implementations.Networking
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error resolving hostname");
+ _logger.LogError(ex, "Error resolving hostname");
}
}
}
@@ -381,56 +359,41 @@ namespace Emby.Server.Implementations.Networking
return Dns.GetHostAddressesAsync(hostName);
}
- private List<IPAddress> GetIPsDefault(bool ignoreVirtualInterface)
+ private IEnumerable<IPAddress> GetIPsDefault(bool ignoreVirtualInterface)
{
- NetworkInterface[] interfaces;
+ IEnumerable<NetworkInterface> interfaces;
try
{
- var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown };
-
interfaces = NetworkInterface.GetAllNetworkInterfaces()
- .Where(i => validStatuses.Contains(i.OperationalStatus))
- .ToArray();
+ .Where(x => x.OperationalStatus == OperationalStatus.Up
+ || x.OperationalStatus == OperationalStatus.Unknown);
}
- catch (Exception ex)
+ catch (NetworkInformationException ex)
{
- Logger.LogError(ex, "Error in GetAllNetworkInterfaces");
- return new List<IPAddress>();
+ _logger.LogError(ex, "Error in GetAllNetworkInterfaces");
+ return Enumerable.Empty<IPAddress>();
}
return interfaces.SelectMany(network =>
{
+ var ipProperties = network.GetIPProperties();
- try
- {
- // suppress logging because it might be causing nas device wake up
- //logger.LogDebug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
-
- var ipProperties = network.GetIPProperties();
-
- // Try to exclude virtual adapters
- // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
- var addr = ipProperties.GatewayAddresses.FirstOrDefault();
- if (addr == null || ignoreVirtualInterface && string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase))
- {
- return new List<IPAddress>();
- }
-
- return ipProperties.UnicastAddresses
- .Select(i => i.Address)
- .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6)
- .ToList();
- }
- catch (Exception ex)
+ // Try to exclude virtual adapters
+ // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
+ var addr = ipProperties.GatewayAddresses.FirstOrDefault();
+ if (addr == null
+ || (ignoreVirtualInterface
+ && (addr.Address.Equals(IPAddress.Any) || addr.Address.Equals(IPAddress.IPv6Any))))
{
- Logger.LogError(ex, "Error querying network interface");
- return new List<IPAddress>();
+ return Enumerable.Empty<IPAddress>();
}
+ return ipProperties.UnicastAddresses
+ .Select(i => i.Address)
+ .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6);
}).GroupBy(i => i.ToString())
- .Select(x => x.First())
- .ToList();
+ .Select(x => x.First());
}
private static async Task<IEnumerable<IPAddress>> GetLocalIpAddressesFallback()
@@ -462,47 +425,27 @@ namespace Emby.Server.Implementations.Networking
var localEndPoint = new IPEndPoint(IPAddress.Any, 0);
using (var udpClient = new UdpClient(localEndPoint))
{
- var port = ((IPEndPoint)(udpClient.Client.LocalEndPoint)).Port;
+ var port = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
return port;
}
}
- private List<string> _macAddresses;
- public List<string> GetMacAddresses()
+ private List<PhysicalAddress> _macAddresses;
+ public List<PhysicalAddress> GetMacAddresses()
{
if (_macAddresses == null)
{
- _macAddresses = GetMacAddressesInternal();
+ _macAddresses = GetMacAddressesInternal().ToList();
}
+
return _macAddresses;
}
- private static List<string> GetMacAddressesInternal()
- {
- return NetworkInterface.GetAllNetworkInterfaces()
+ private static IEnumerable<PhysicalAddress> GetMacAddressesInternal()
+ => NetworkInterface.GetAllNetworkInterfaces()
.Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback)
- .Select(i =>
- {
- try
- {
- var physicalAddress = i.GetPhysicalAddress();
-
- if (physicalAddress == null)
- {
- return null;
- }
-
- return physicalAddress.ToString();
- }
- catch (Exception)
- {
- //TODO Log exception.
- return null;
- }
- })
- .Where(i => i != null)
- .ToList();
- }
+ .Select(x => x.GetPhysicalAddress())
+ .Where(x => x != null && x != PhysicalAddress.None);
/// <summary>
/// Parses the specified endpointstring.
@@ -612,32 +555,10 @@ namespace Emby.Server.Implementations.Networking
return hosts[0];
}
- public IpAddressInfo ParseIpAddress(string ipAddress)
- {
- if (TryParseIpAddress(ipAddress, out var info))
- {
- return info;
- }
-
- throw new ArgumentException("Invalid ip address: " + ipAddress);
- }
-
- public bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo)
- {
- if (IPAddress.TryParse(ipAddress, out var address))
- {
- ipAddressInfo = ToIpAddressInfo(address);
- return true;
- }
-
- ipAddressInfo = null;
- return false;
- }
-
- public bool IsInSameSubnet(IpAddressInfo address1, IpAddressInfo address2, IpAddressInfo subnetMask)
+ public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask)
{
- IPAddress network1 = GetNetworkAddress(ToIPAddress(address1), ToIPAddress(subnetMask));
- IPAddress network2 = GetNetworkAddress(ToIPAddress(address2), ToIPAddress(subnetMask));
+ IPAddress network1 = GetNetworkAddress(address1, subnetMask);
+ IPAddress network2 = GetNetworkAddress(address2, subnetMask);
return network1.Equals(network2);
}
@@ -656,13 +577,13 @@ namespace Emby.Server.Implementations.Networking
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
}
+
return new IPAddress(broadcastAddress);
}
- public IpAddressInfo GetLocalIpSubnetMask(IpAddressInfo address)
+ public IPAddress GetLocalIpSubnetMask(IPAddress address)
{
NetworkInterface[] interfaces;
- IPAddress ipaddress = ToIPAddress(address);
try
{
@@ -674,7 +595,7 @@ namespace Emby.Server.Implementations.Networking
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error in GetAllNetworkInterfaces");
+ _logger.LogError(ex, "Error in GetAllNetworkInterfaces");
return null;
}
@@ -684,83 +605,15 @@ namespace Emby.Server.Implementations.Networking
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
- if (ip.Address.Equals(ipaddress) && ip.IPv4Mask != null)
+ if (ip.Address.Equals(address) && ip.IPv4Mask != null)
{
- return ToIpAddressInfo(ip.IPv4Mask);
+ return ip.IPv4Mask;
}
}
}
}
- return null;
- }
-
- public static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint)
- {
- if (endpoint == null)
- {
- return null;
- }
-
- return new IpEndPointInfo(ToIpAddressInfo(endpoint.Address), endpoint.Port);
- }
-
- public static IPEndPoint ToIPEndPoint(IpEndPointInfo endpoint)
- {
- if (endpoint == null)
- {
- return null;
- }
- return new IPEndPoint(ToIPAddress(endpoint.IpAddress), endpoint.Port);
- }
-
- public static IPAddress ToIPAddress(IpAddressInfo address)
- {
- if (address.Equals(IpAddressInfo.Any))
- {
- return IPAddress.Any;
- }
- if (address.Equals(IpAddressInfo.IPv6Any))
- {
- return IPAddress.IPv6Any;
- }
- if (address.Equals(IpAddressInfo.Loopback))
- {
- return IPAddress.Loopback;
- }
- if (address.Equals(IpAddressInfo.IPv6Loopback))
- {
- return IPAddress.IPv6Loopback;
- }
-
- return IPAddress.Parse(address.Address);
- }
-
- public static IpAddressInfo ToIpAddressInfo(IPAddress address)
- {
- if (address.Equals(IPAddress.Any))
- {
- return IpAddressInfo.Any;
- }
- if (address.Equals(IPAddress.IPv6Any))
- {
- return IpAddressInfo.IPv6Any;
- }
- if (address.Equals(IPAddress.Loopback))
- {
- return IpAddressInfo.Loopback;
- }
- if (address.Equals(IPAddress.IPv6Loopback))
- {
- return IpAddressInfo.IPv6Loopback;
- }
- return new IpAddressInfo(address.ToString(), address.AddressFamily == AddressFamily.InterNetworkV6 ? IpAddressFamily.InterNetworkV6 : IpAddressFamily.InterNetwork);
- }
-
- public async Task<IpAddressInfo[]> GetHostAddressesAsync(string host)
- {
- var addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
- return addresses.Select(ToIpAddressInfo).ToArray();
+ return null;
}
/// <summary>
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 29836e0bf..40b568b40 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -129,7 +130,7 @@ namespace Emby.Server.Implementations.Playlists
{
new Share
{
- UserId = options.UserId.Equals(Guid.Empty) ? null : options.UserId.ToString("N"),
+ UserId = options.UserId.Equals(Guid.Empty) ? null : options.UserId.ToString("N", CultureInfo.InvariantCulture),
CanEdit = true
}
}
@@ -144,7 +145,7 @@ namespace Emby.Server.Implementations.Playlists
if (options.ItemIdList.Length > 0)
{
- AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user, new DtoOptions(false)
+ AddToPlaylistInternal(playlist.Id.ToString("N", CultureInfo.InvariantCulture), options.ItemIdList, user, new DtoOptions(false)
{
EnableImages = true
});
@@ -152,7 +153,7 @@ namespace Emby.Server.Implementations.Playlists
return new PlaylistCreationResult
{
- Id = playlist.Id.ToString("N")
+ Id = playlist.Id.ToString("N", CultureInfo.InvariantCulture)
};
}
finally
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 08bb39578..83226b07f 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -1,5 +1,5 @@
using System;
-using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -287,7 +287,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
if (_id == null)
{
- _id = ScheduledTask.GetType().FullName.GetMD5().ToString("N");
+ _id = ScheduledTask.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
return _id;
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index 545e11bf9..0b5ee5d03 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -97,7 +97,7 @@ namespace Emby.Server.Implementations.Security
statement.TryBind("@AppName", info.AppName);
statement.TryBind("@AppVersion", info.AppVersion);
statement.TryBind("@DeviceName", info.DeviceName);
- statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N")));
+ statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture)));
statement.TryBind("@UserName", info.UserName);
statement.TryBind("@IsActive", true);
statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue());
@@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.Security
statement.TryBind("@AppName", info.AppName);
statement.TryBind("@AppVersion", info.AppVersion);
statement.TryBind("@DeviceName", info.DeviceName);
- statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N")));
+ statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture)));
statement.TryBind("@UserName", info.UserName);
statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue());
statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue());
@@ -174,7 +174,7 @@ namespace Emby.Server.Implementations.Security
if (!query.UserId.Equals(Guid.Empty))
{
- statement.TryBind("@UserId", query.UserId.ToString("N"));
+ statement.TryBind("@UserId", query.UserId.ToString("N", CultureInfo.InvariantCulture));
}
if (!string.IsNullOrEmpty(query.DeviceId))
diff --git a/Emby.Server.Implementations/Serialization/JsonSerializer.cs b/Emby.Server.Implementations/Serialization/JsonSerializer.cs
index 8ae7fd90c..36196ee36 100644
--- a/Emby.Server.Implementations/Serialization/JsonSerializer.cs
+++ b/Emby.Server.Implementations/Serialization/JsonSerializer.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using MediaBrowser.Model.IO;
@@ -245,7 +246,7 @@ namespace Emby.Server.Implementations.Serialization
return null;
}
- return guid.ToString("N");
+ return guid.ToString("N", CultureInfo.InvariantCulture);
}
/// <summary>
diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs
index adaf23234..2f5a8af80 100644
--- a/Emby.Server.Implementations/ServerApplicationPaths.cs
+++ b/Emby.Server.Implementations/ServerApplicationPaths.cs
@@ -10,8 +10,12 @@ namespace Emby.Server.Implementations
/// </summary>
public class ServerApplicationPaths : BaseApplicationPaths, IServerApplicationPaths
{
+ private string _defaultTranscodingTempPath;
+ private string _transcodingTempPath;
+ private string _internalMetadataPath;
+
/// <summary>
- /// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class.
+ /// Initializes a new instance of the <see cref="ServerApplicationPaths" /> class.
/// </summary>
public ServerApplicationPaths(
string programDataPath,
@@ -30,7 +34,7 @@ namespace Emby.Server.Implementations
public string ApplicationResourcesPath { get; } = AppContext.BaseDirectory;
/// <summary>
- /// Gets the path to the base root media directory
+ /// Gets the path to the base root media directory.
/// </summary>
/// <value>The root folder path.</value>
public string RootFolderPath => Path.Combine(ProgramDataPath, "root");
@@ -48,7 +52,7 @@ namespace Emby.Server.Implementations
public string LocalizationPath => Path.Combine(ProgramDataPath, "localization");
/// <summary>
- /// Gets the path to the People directory
+ /// Gets the path to the People directory.
/// </summary>
/// <value>The people path.</value>
public string PeoplePath => Path.Combine(InternalMetadataPath, "People");
@@ -56,37 +60,37 @@ namespace Emby.Server.Implementations
public string ArtistsPath => Path.Combine(InternalMetadataPath, "artists");
/// <summary>
- /// Gets the path to the Genre directory
+ /// Gets the path to the Genre directory.
/// </summary>
/// <value>The genre path.</value>
public string GenrePath => Path.Combine(InternalMetadataPath, "Genre");
/// <summary>
- /// Gets the path to the Genre directory
+ /// Gets the path to the Genre directory.
/// </summary>
/// <value>The genre path.</value>
public string MusicGenrePath => Path.Combine(InternalMetadataPath, "MusicGenre");
/// <summary>
- /// Gets the path to the Studio directory
+ /// Gets the path to the Studio directory.
/// </summary>
/// <value>The studio path.</value>
public string StudioPath => Path.Combine(InternalMetadataPath, "Studio");
/// <summary>
- /// Gets the path to the Year directory
+ /// Gets the path to the Year directory.
/// </summary>
/// <value>The year path.</value>
public string YearPath => Path.Combine(InternalMetadataPath, "Year");
/// <summary>
- /// Gets the path to the General IBN directory
+ /// Gets the path to the General IBN directory.
/// </summary>
/// <value>The general path.</value>
public string GeneralPath => Path.Combine(InternalMetadataPath, "general");
/// <summary>
- /// Gets the path to the Ratings IBN directory
+ /// Gets the path to the Ratings IBN directory.
/// </summary>
/// <value>The ratings path.</value>
public string RatingsPath => Path.Combine(InternalMetadataPath, "ratings");
@@ -98,15 +102,13 @@ namespace Emby.Server.Implementations
public string MediaInfoImagesPath => Path.Combine(InternalMetadataPath, "mediainfo");
/// <summary>
- /// Gets the path to the user configuration directory
+ /// Gets the path to the user configuration directory.
/// </summary>
/// <value>The user configuration directory path.</value>
public string UserConfigurationDirectoryPath => Path.Combine(ConfigurationDirectoryPath, "users");
- private string _defaultTranscodingTempPath;
public string DefaultTranscodingTempPath => _defaultTranscodingTempPath ?? (_defaultTranscodingTempPath = Path.Combine(ProgramDataPath, "transcoding-temp"));
- private string _transcodingTempPath;
public string TranscodingTempPath
{
get => _transcodingTempPath ?? (_transcodingTempPath = DefaultTranscodingTempPath);
@@ -139,7 +141,6 @@ namespace Emby.Server.Implementations
return path;
}
- private string _internalMetadataPath;
public string InternalMetadataPath
{
get => _internalMetadataPath ?? (_internalMetadataPath = Path.Combine(DataPath, "metadata"));
diff --git a/Emby.Server.Implementations/Services/HttpResult.cs b/Emby.Server.Implementations/Services/HttpResult.cs
index 2b5963a77..095193828 100644
--- a/Emby.Server.Implementations/Services/HttpResult.cs
+++ b/Emby.Server.Implementations/Services/HttpResult.cs
@@ -10,8 +10,6 @@ namespace Emby.Server.Implementations.Services
public class HttpResult
: IHttpResult, IAsyncStreamWriter
{
- public object Response { get; set; }
-
public HttpResult(object response, string contentType, HttpStatusCode statusCode)
{
this.Headers = new Dictionary<string, string>();
@@ -21,6 +19,8 @@ namespace Emby.Server.Implementations.Services
this.StatusCode = statusCode;
}
+ public object Response { get; set; }
+
public string ContentType { get; set; }
public IDictionary<string, string> Headers { get; private set; }
@@ -37,7 +37,7 @@ namespace Emby.Server.Implementations.Services
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
{
- var response = RequestContext == null ? null : RequestContext.Response;
+ var response = RequestContext?.Response;
if (this.Response is byte[] bytesResponse)
{
@@ -45,13 +45,14 @@ namespace Emby.Server.Implementations.Services
if (response != null)
{
- response.OriginalResponse.ContentLength = contentLength;
+ response.ContentLength = contentLength;
}
if (contentLength > 0)
{
await responseStream.WriteAsync(bytesResponse, 0, contentLength, cancellationToken).ConfigureAwait(false);
}
+
return;
}
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index 251ba3529..ca2b22fe0 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
@@ -7,13 +6,14 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
+using Microsoft.AspNetCore.Http;
using MediaBrowser.Model.Services;
namespace Emby.Server.Implementations.Services
{
public static class ResponseHelper
{
- public static Task WriteToResponse(IResponse response, IRequest request, object result, CancellationToken cancellationToken)
+ public static Task WriteToResponse(HttpResponse response, IRequest request, object result, CancellationToken cancellationToken)
{
if (result == null)
{
@@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Services
response.StatusCode = (int)HttpStatusCode.NoContent;
}
- response.OriginalResponse.ContentLength = 0;
+ response.ContentLength = 0;
return Task.CompletedTask;
}
@@ -41,7 +41,6 @@ namespace Emby.Server.Implementations.Services
httpResult.RequestContext = request;
response.StatusCode = httpResult.Status;
- response.StatusDescription = httpResult.StatusCode.ToString();
}
var responseOptions = result as IHasHeaders;
@@ -51,11 +50,11 @@ namespace Emby.Server.Implementations.Services
{
if (string.Equals(responseHeaders.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
{
- response.OriginalResponse.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture);
+ response.ContentLength = long.Parse(responseHeaders.Value, CultureInfo.InvariantCulture);
continue;
}
- response.AddHeader(responseHeaders.Key, responseHeaders.Value);
+ response.Headers.Add(responseHeaders.Key, responseHeaders.Value);
}
}
@@ -74,31 +73,31 @@ namespace Emby.Server.Implementations.Services
switch (result)
{
case IAsyncStreamWriter asyncStreamWriter:
- return asyncStreamWriter.WriteToAsync(response.OutputStream, cancellationToken);
+ return asyncStreamWriter.WriteToAsync(response.Body, cancellationToken);
case IStreamWriter streamWriter:
- streamWriter.WriteTo(response.OutputStream);
+ streamWriter.WriteTo(response.Body);
return Task.CompletedTask;
case FileWriter fileWriter:
return fileWriter.WriteToAsync(response, cancellationToken);
case Stream stream:
- return CopyStream(stream, response.OutputStream);
+ return CopyStream(stream, response.Body);
case byte[] bytes:
response.ContentType = "application/octet-stream";
- response.OriginalResponse.ContentLength = bytes.Length;
+ response.ContentLength = bytes.Length;
if (bytes.Length > 0)
{
- return response.OutputStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+ return response.Body.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
return Task.CompletedTask;
case string responseText:
var responseTextAsBytes = Encoding.UTF8.GetBytes(responseText);
- response.OriginalResponse.ContentLength = responseTextAsBytes.Length;
+ response.ContentLength = responseTextAsBytes.Length;
if (responseTextAsBytes.Length > 0)
{
- return response.OutputStream.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken);
+ return response.Body.WriteAsync(responseTextAsBytes, 0, responseTextAsBytes.Length, cancellationToken);
}
return Task.CompletedTask;
@@ -115,7 +114,7 @@ namespace Emby.Server.Implementations.Services
}
}
- public static async Task WriteObject(IRequest request, object result, IResponse response)
+ public static async Task WriteObject(IRequest request, object result, HttpResponse response)
{
var contentType = request.ResponseContentType;
var serializer = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType);
@@ -127,11 +126,11 @@ namespace Emby.Server.Implementations.Services
ms.Position = 0;
var contentLength = ms.Length;
- response.OriginalResponse.ContentLength = contentLength;
+ response.ContentLength = contentLength;
if (contentLength > 0)
{
- await ms.CopyToAsync(response.OutputStream).ConfigureAwait(false);
+ await ms.CopyToAsync(response.Body).ConfigureAwait(false);
}
}
}
diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs
index 5e3d529c6..d963f9043 100644
--- a/Emby.Server.Implementations/Services/ServiceController.cs
+++ b/Emby.Server.Implementations/Services/ServiceController.cs
@@ -147,7 +147,6 @@ namespace Emby.Server.Implementations.Services
public Task<object> Execute(HttpListenerHost httpHost, object requestDto, IRequest req)
{
- req.Dto = requestDto;
var requestType = requestDto.GetType();
req.OperationName = requestType.Name;
@@ -161,9 +160,6 @@ namespace Emby.Server.Implementations.Services
serviceRequiresContext.Request = req;
}
- if (req.Dto == null) // Don't override existing batched DTO[]
- req.Dto = requestDto;
-
//Executes the service and returns the result
return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
}
diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs
index 38952628d..9124b9c14 100644
--- a/Emby.Server.Implementations/Services/ServiceExec.cs
+++ b/Emby.Server.Implementations/Services/ServiceExec.cs
@@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.Services
foreach (var requestFilter in actionContext.RequestFilters)
{
requestFilter.RequestFilter(request, request.Response, requestDto);
- if (request.Response.OriginalResponse.HasStarted)
+ if (request.Response.HasStarted)
{
Task.FromResult<object>(null);
}
diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs
index d32fce1c7..934560de3 100644
--- a/Emby.Server.Implementations/Services/ServiceHandler.cs
+++ b/Emby.Server.Implementations/Services/ServiceHandler.cs
@@ -5,20 +5,21 @@ using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.HttpServer;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Services
{
public class ServiceHandler
{
- public RestPath RestPath { get; }
+ private RestPath _restPath;
- public string ResponseContentType { get; }
+ private string _responseContentType;
internal ServiceHandler(RestPath restPath, string responseContentType)
{
- RestPath = restPath;
- ResponseContentType = responseContentType;
+ _restPath = restPath;
+ _responseContentType = responseContentType;
}
protected static Task<object> CreateContentTypeRequest(HttpListenerHost host, IRequest httpReq, Type requestType, string contentType)
@@ -54,7 +55,7 @@ namespace Emby.Server.Implementations.Services
private static string GetFormatContentType(string format)
{
- //built-in formats
+ // built-in formats
switch (format)
{
case "json": return "application/json";
@@ -63,16 +64,16 @@ namespace Emby.Server.Implementations.Services
}
}
- public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, IResponse httpRes, ILogger logger, CancellationToken cancellationToken)
+ public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, HttpResponse httpRes, ILogger logger, CancellationToken cancellationToken)
{
- httpReq.Items["__route"] = RestPath;
+ httpReq.Items["__route"] = _restPath;
- if (ResponseContentType != null)
+ if (_responseContentType != null)
{
- httpReq.ResponseContentType = ResponseContentType;
+ httpReq.ResponseContentType = _responseContentType;
}
- var request = httpReq.Dto = await CreateRequest(httpHost, httpReq, RestPath, logger).ConfigureAwait(false);
+ var request = await CreateRequest(httpHost, httpReq, _restPath, logger).ConfigureAwait(false);
httpHost.ApplyRequestFilters(httpReq, httpRes, request);
@@ -94,7 +95,7 @@ namespace Emby.Server.Implementations.Services
if (RequireqRequestStream(requestType))
{
// Used by IRequiresRequestStream
- var requestParams = await GetRequestParams(httpReq).ConfigureAwait(false);
+ var requestParams = GetRequestParams(httpReq.Response.HttpContext.Request);
var request = ServiceHandler.CreateRequest(httpReq, restPath, requestParams, host.CreateInstance(requestType));
var rawReq = (IRequiresRequestStream)request;
@@ -103,7 +104,7 @@ namespace Emby.Server.Implementations.Services
}
else
{
- var requestParams = await GetFlattenedRequestParams(httpReq).ConfigureAwait(false);
+ var requestParams = GetFlattenedRequestParams(httpReq.Response.HttpContext.Request);
var requestDto = await CreateContentTypeRequest(host, httpReq, restPath.RequestType, httpReq.ContentType).ConfigureAwait(false);
@@ -121,7 +122,7 @@ namespace Emby.Server.Implementations.Services
public static object CreateRequest(IRequest httpReq, RestPath restPath, Dictionary<string, string> requestParams, object requestDto)
{
var pathInfo = !restPath.IsWildCardPath
- ? GetSanitizedPathInfo(httpReq.PathInfo, out string contentType)
+ ? GetSanitizedPathInfo(httpReq.PathInfo, out _)
: httpReq.PathInfo;
return restPath.CreateRequest(pathInfo, requestParams, requestDto);
@@ -130,56 +131,41 @@ namespace Emby.Server.Implementations.Services
/// <summary>
/// Duplicate Params are given a unique key by appending a #1 suffix
/// </summary>
- private static async Task<Dictionary<string, string>> GetRequestParams(IRequest request)
+ private static Dictionary<string, string> GetRequestParams(HttpRequest request)
{
var map = new Dictionary<string, string>();
- foreach (var name in request.QueryString.Keys)
+ foreach (var pair in request.Query)
{
- if (name == null)
- {
- // thank you ASP.NET
- continue;
- }
-
- var values = request.QueryString[name];
+ var values = pair.Value;
if (values.Count == 1)
{
- map[name] = values[0];
+ map[pair.Key] = values[0];
}
else
{
for (var i = 0; i < values.Count; i++)
{
- map[name + (i == 0 ? "" : "#" + i)] = values[i];
+ map[pair.Key + (i == 0 ? string.Empty : "#" + i)] = values[i];
}
}
}
- if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
+ if ((IsMethod(request.Method, "POST") || IsMethod(request.Method, "PUT"))
+ && request.HasFormContentType)
{
- var formData = await request.GetFormData().ConfigureAwait(false);
- if (formData != null)
+ foreach (var pair in request.Form)
{
- foreach (var name in formData.Keys)
+ var values = pair.Value;
+ if (values.Count == 1)
{
- if (name == null)
- {
- // thank you ASP.NET
- continue;
- }
-
- var values = formData.GetValues(name);
- if (values.Count == 1)
- {
- map[name] = values[0];
- }
- else
+ map[pair.Key] = values[0];
+ }
+ else
+ {
+ for (var i = 0; i < values.Count; i++)
{
- for (var i = 0; i < values.Count; i++)
- {
- map[name + (i == 0 ? "" : "#" + i)] = values[i];
- }
+ map[pair.Key + (i == 0 ? string.Empty : "#" + i)] = values[i];
}
}
}
@@ -189,43 +175,26 @@ namespace Emby.Server.Implementations.Services
}
private static bool IsMethod(string method, string expected)
- {
- return string.Equals(method, expected, StringComparison.OrdinalIgnoreCase);
- }
+ => string.Equals(method, expected, StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Duplicate params have their values joined together in a comma-delimited string
/// </summary>
- private static async Task<Dictionary<string, string>> GetFlattenedRequestParams(IRequest request)
+ private static Dictionary<string, string> GetFlattenedRequestParams(HttpRequest request)
{
var map = new Dictionary<string, string>();
- foreach (var name in request.QueryString.Keys)
+ foreach (var pair in request.Query)
{
- if (name == null)
- {
- // thank you ASP.NET
- continue;
- }
-
- map[name] = request.QueryString[name];
+ map[pair.Key] = pair.Value;
}
- if ((IsMethod(request.Verb, "POST") || IsMethod(request.Verb, "PUT")))
+ if ((IsMethod(request.Method, "POST") || IsMethod(request.Method, "PUT"))
+ && request.HasFormContentType)
{
- var formData = await request.GetFormData().ConfigureAwait(false);
- if (formData != null)
+ foreach (var pair in request.Form)
{
- foreach (var name in formData.Keys)
- {
- if (name == null)
- {
- // thank you ASP.NET
- continue;
- }
-
- map[name] = formData[name];
- }
+ map[pair.Key] = pair.Value;
}
}
diff --git a/Emby.Server.Implementations/Session/HttpSessionController.cs b/Emby.Server.Implementations/Session/HttpSessionController.cs
index 9281f82b3..1104a7a85 100644
--- a/Emby.Server.Implementations/Session/HttpSessionController.cs
+++ b/Emby.Server.Implementations/Session/HttpSessionController.cs
@@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Session
{
var dict = new Dictionary<string, string>();
- dict["ItemIds"] = string.Join(",", command.ItemIds.Select(i => i.ToString("N")).ToArray());
+ dict["ItemIds"] = string.Join(",", command.ItemIds.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray());
if (command.StartPositionTicks.HasValue)
{
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 53ed5fc22..0347100a4 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -327,7 +327,7 @@ namespace Emby.Server.Implementations.Session
{
if (string.IsNullOrEmpty(info.MediaSourceId))
{
- info.MediaSourceId = info.ItemId.ToString("N");
+ info.MediaSourceId = info.ItemId.ToString("N", CultureInfo.InvariantCulture);
}
if (!info.ItemId.Equals(Guid.Empty) && info.Item == null && libraryItem != null)
@@ -463,7 +463,7 @@ namespace Emby.Server.Implementations.Session
Client = appName,
DeviceId = deviceId,
ApplicationVersion = appVersion,
- Id = key.GetMD5().ToString("N"),
+ Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture),
ServerId = _appHost.SystemId
};
@@ -845,7 +845,7 @@ namespace Emby.Server.Implementations.Session
// Normalize
if (string.IsNullOrEmpty(info.MediaSourceId))
{
- info.MediaSourceId = info.ItemId.ToString("N");
+ info.MediaSourceId = info.ItemId.ToString("N", CultureInfo.InvariantCulture);
}
if (!info.ItemId.Equals(Guid.Empty) && info.Item == null && libraryItem != null)
@@ -1029,7 +1029,7 @@ namespace Emby.Server.Implementations.Session
private static async Task SendMessageToSession<T>(SessionInfo session, string name, T data, CancellationToken cancellationToken)
{
var controllers = session.SessionControllers.ToArray();
- var messageId = Guid.NewGuid().ToString("N");
+ var messageId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
foreach (var controller in controllers)
{
@@ -1041,7 +1041,7 @@ namespace Emby.Server.Implementations.Session
{
IEnumerable<Task> GetTasks()
{
- var messageId = Guid.NewGuid().ToString("N");
+ var messageId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
foreach (var session in sessions)
{
var controllers = session.SessionControllers;
@@ -1234,7 +1234,7 @@ namespace Emby.Server.Implementations.Session
AssertCanControl(session, controllingSession);
if (!controllingSession.UserId.Equals(Guid.Empty))
{
- command.ControllingUserId = controllingSession.UserId.ToString("N");
+ command.ControllingUserId = controllingSession.UserId.ToString("N", CultureInfo.InvariantCulture);
}
}
@@ -1484,7 +1484,7 @@ namespace Emby.Server.Implementations.Session
DeviceId = deviceId,
DeviceName = deviceName,
UserId = user.Id,
- AccessToken = Guid.NewGuid().ToString("N"),
+ AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
UserName = user.Name
};
@@ -1822,6 +1822,7 @@ namespace Emby.Server.Implementations.Session
CheckDisposed();
var sessions = Sessions.Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase));
+
return SendMessageToSessions(sessions, name, data, cancellationToken);
}
@@ -1831,6 +1832,7 @@ namespace Emby.Server.Implementations.Session
var sessions = Sessions
.Where(i => string.Equals(i.DeviceId, deviceId, StringComparison.OrdinalIgnoreCase) || IsAdminSession(i));
+
return SendMessageToSessions(sessions, name, data, cancellationToken);
}
diff --git a/Emby.Server.Implementations/SocketSharp/RequestMono.cs b/Emby.Server.Implementations/SocketSharp/RequestMono.cs
deleted file mode 100644
index ec637186f..000000000
--- a/Emby.Server.Implementations/SocketSharp/RequestMono.cs
+++ /dev/null
@@ -1,647 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Primitives;
-using Microsoft.Net.Http.Headers;
-
-namespace Emby.Server.Implementations.SocketSharp
-{
- public partial class WebSocketSharpRequest : IHttpRequest
- {
- internal static string GetParameter(ReadOnlySpan<char> header, string attr)
- {
- int ap = header.IndexOf(attr.AsSpan(), StringComparison.Ordinal);
- if (ap == -1)
- {
- return null;
- }
-
- ap += attr.Length;
- if (ap >= header.Length)
- {
- return null;
- }
-
- char ending = header[ap];
- if (ending != '"')
- {
- ending = ' ';
- }
-
- var slice = header.Slice(ap + 1);
- int end = slice.IndexOf(ending);
- if (end == -1)
- {
- return ending == '"' ? null : header.Slice(ap).ToString();
- }
-
- return slice.Slice(0, end - ap - 1).ToString();
- }
-
- private async Task LoadMultiPart(WebROCollection form)
- {
- string boundary = GetParameter(ContentType.AsSpan(), "; 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;
- await input.ReadAsync(copy, 0, (int)e.Length).ConfigureAwait(false);
-
- 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,
- files[e.Name] = new HttpPostedFile(e.Filename, e.ContentType, input, e.Start, e.Length);
- }
- }
- }
- }
-
- public async Task<QueryParamCollection> GetFormData()
- {
- var form = new WebROCollection();
- files = new Dictionary<string, HttpPostedFile>();
-
- if (IsContentType("multipart/form-data"))
- {
- await LoadMultiPart(form).ConfigureAwait(false);
- }
- else if (IsContentType("application/x-www-form-urlencoded"))
- {
- await LoadWwwForm(form).ConfigureAwait(false);
- }
-
- if (validate_form && !checked_form)
- {
- checked_form = true;
- ValidateNameValueCollection("Form", form);
- }
-
- return form;
- }
-
- public string Accept => StringValues.IsNullOrEmpty(request.Headers[HeaderNames.Accept]) ? null : request.Headers[HeaderNames.Accept].ToString();
-
- public string Authorization => StringValues.IsNullOrEmpty(request.Headers[HeaderNames.Authorization]) ? null : request.Headers[HeaderNames.Authorization].ToString();
-
- protected bool validate_form { get; set; }
- protected bool checked_form { get; set; }
-
- private 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(
- CultureInfo.InvariantCulture,
- "A potentially dangerous Request.{0} value was detected from the client ({1}={2}).",
- name,
- key,
- v);
-
- throw new Exception(msg);
- }
-
- private 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)
- => IsInvalidString(val, out var 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;
- }
-
- private bool IsContentType(string ct)
- {
- if (ContentType == null)
- {
- return false;
- }
-
- return ContentType.StartsWith(ct, StringComparison.OrdinalIgnoreCase);
- }
-
- private async Task LoadWwwForm(WebROCollection form)
- {
- using (var input = InputStream)
- {
- using (var ms = new MemoryStream())
- {
- await input.CopyToAsync(ms).ConfigureAwait(false);
- ms.Position = 0;
-
- using (var s = new StreamReader(ms, ContentEncoding))
- {
- var key = new StringBuilder();
- var 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);
- }
- }
- }
- }
- }
-
- private static void AddRawKeyValue(WebROCollection form, StringBuilder key, StringBuilder value)
- {
- form.Add(WebUtility.UrlDecode(key.ToString()), WebUtility.UrlDecode(value.ToString()));
-
- key.Length = 0;
- value.Length = 0;
- }
-
- private Dictionary<string, HttpPostedFile> files;
-
- private class WebROCollection : QueryParamCollection
- {
- public override string ToString()
- {
- var 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();
- }
- }
- private class HttpMultipart
- {
-
- public class Element
- {
- 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()
- {
- return "ContentType " + ContentType + ", Name " + Name + ", Filename " + Filename + ", Start " +
- Start.ToString(CultureInfo.CurrentCulture) + ", Length " + Length.ToString(CultureInfo.CurrentCulture);
- }
- }
-
- private const byte LF = (byte)'\n';
-
- private const byte CR = (byte)'\r';
-
- private Stream data;
-
- private string boundary;
-
- private byte[] boundaryBytes;
-
- private byte[] buffer;
-
- private bool atEof;
-
- private Encoding encoding;
-
- private StringBuilder sb;
-
- // 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;
- boundary = b;
- boundaryBytes = encoding.GetBytes(b);
- buffer = new byte[boundaryBytes.Length + 2]; // CRLF or '--'
- this.encoding = encoding;
- sb = new StringBuilder();
- }
-
- public Element ReadNextElement()
- {
- if (atEof || ReadBoundary())
- {
- return null;
- }
-
- var elem = new Element();
- ReadOnlySpan<char> header;
- while ((header = ReadLine().AsSpan()).Length != 0)
- {
- if (header.StartsWith("Content-Disposition:".AsSpan(), StringComparison.OrdinalIgnoreCase))
- {
- elem.Name = GetContentDispositionAttribute(header, "name");
- elem.Filename = StripPath(GetContentDispositionAttributeWithEncoding(header, "filename"));
- }
- else if (header.StartsWith("Content-Type:".AsSpan(), StringComparison.OrdinalIgnoreCase))
- {
- elem.ContentType = header.Slice("Content-Type:".Length).Trim().ToString();
- 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()
- {
- // 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();
- }
-
- private static string GetContentDispositionAttribute(ReadOnlySpan<char> l, string name)
- {
- int idx = l.IndexOf((name + "=\"").AsSpan(), StringComparison.Ordinal);
- if (idx < 0)
- {
- return null;
- }
-
- int begin = idx + name.Length + "=\"".Length;
- int end = l.Slice(begin).IndexOf('"');
- if (end < 0)
- {
- return null;
- }
-
- if (begin == end)
- {
- return string.Empty;
- }
-
- return l.Slice(begin, end - begin).ToString();
- }
-
- private string GetContentDispositionAttributeWithEncoding(ReadOnlySpan<char> l, string name)
- {
- int idx = l.IndexOf((name + "=\"").AsSpan(), StringComparison.Ordinal);
- if (idx < 0)
- {
- return null;
- }
-
- int begin = idx + name.Length + "=\"".Length;
- int end = l.Slice(begin).IndexOf('"');
- if (end < 0)
- {
- return null;
- }
-
- if (begin == end)
- {
- return string.Empty;
- }
-
- ReadOnlySpan<char> temp = l.Slice(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);
- }
-
- private bool ReadBoundary()
- {
- try
- {
- string line;
- do
- {
- line = ReadLine();
- }
- while (line.Length == 0);
-
- if (line[0] != '-' || line[1] != '-')
- {
- return false;
- }
-
- if (!line.EndsWith(boundary, StringComparison.Ordinal))
- {
- return true;
- }
- }
- catch
- {
-
- }
-
- return false;
- }
-
- private static bool CompareBytes(byte[] orig, byte[] other)
- {
- for (int i = orig.Length - 1; i >= 0; i--)
- {
- if (orig[i] != other[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- private 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(boundaryBytes, 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] == '-')
- {
- atEof = 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;
- }
-
- private static string StripPath(string path)
- {
- if (path == null || path.Length == 0)
- {
- return path;
- }
-
- if (path.IndexOf(":\\", StringComparison.Ordinal) != 1
- && !path.StartsWith("\\\\", StringComparison.Ordinal))
- {
- return path;
- }
-
- return path.Substring(path.LastIndexOf('\\') + 1);
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs
index 7a630bf10..332ce3903 100644
--- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs
+++ b/Emby.Server.Implementations/SocketSharp/WebSocketSharpRequest.cs
@@ -1,57 +1,56 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Net;
using System.Linq;
-using System.Text;
using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
-using IHttpFile = MediaBrowser.Model.Services.IHttpFile;
using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest;
-using IResponse = MediaBrowser.Model.Services.IResponse;
namespace Emby.Server.Implementations.SocketSharp
{
public partial class WebSocketSharpRequest : IHttpRequest
{
- private readonly HttpRequest request;
+ public const string FormUrlEncoded = "application/x-www-form-urlencoded";
+ public const string MultiPartFormData = "multipart/form-data";
+ public const string Soap11 = "text/xml; charset=utf-8";
- public WebSocketSharpRequest(HttpRequest httpContext, HttpResponse response, string operationName, ILogger logger)
+ private string _remoteIp;
+ private Dictionary<string, object> _items;
+ private string _responseContentType;
+
+ public WebSocketSharpRequest(HttpRequest httpRequest, HttpResponse httpResponse, string operationName, ILogger logger)
{
this.OperationName = operationName;
- this.request = httpContext;
- this.Response = new WebSocketSharpResponse(logger, response);
+ this.Request = httpRequest;
+ this.Response = httpResponse;
}
- public HttpRequest HttpRequest => request;
+ public string Accept => StringValues.IsNullOrEmpty(Request.Headers[HeaderNames.Accept]) ? null : Request.Headers[HeaderNames.Accept].ToString();
- public IResponse Response { get; }
+ public string Authorization => StringValues.IsNullOrEmpty(Request.Headers[HeaderNames.Authorization]) ? null : Request.Headers[HeaderNames.Authorization].ToString();
- public string OperationName { get; set; }
+ public HttpRequest Request { get; }
- public object Dto { get; set; }
+ public HttpResponse Response { get; }
- public string RawUrl => request.GetEncodedPathAndQuery();
+ public string OperationName { get; set; }
- public string AbsoluteUri => request.GetDisplayUrl().TrimEnd('/');
- // Header[name] returns "" when undefined
+ public string RawUrl => Request.GetEncodedPathAndQuery();
- private string GetHeader(string name) => request.Headers[name].ToString();
+ public string AbsoluteUri => Request.GetDisplayUrl().TrimEnd('/');
- private string remoteIp;
public string RemoteIp
{
get
{
- if (remoteIp != null)
+ if (_remoteIp != null)
{
- return remoteIp;
+ return _remoteIp;
}
IPAddress ip;
@@ -62,14 +61,51 @@ namespace Emby.Server.Implementations.SocketSharp
{
if (!IPAddress.TryParse(GetHeader(CustomHeaderNames.XRealIP), out ip))
{
- ip = request.HttpContext.Connection.RemoteIpAddress;
+ ip = Request.HttpContext.Connection.RemoteIpAddress;
}
}
- return remoteIp = NormalizeIp(ip).ToString();
+ return _remoteIp = NormalizeIp(ip).ToString();
}
}
+ public string[] AcceptTypes => Request.Headers.GetCommaSeparatedValues(HeaderNames.Accept);
+
+ public Dictionary<string, object> Items => _items ?? (_items = new Dictionary<string, object>());
+
+ public string ResponseContentType
+ {
+ get =>
+ _responseContentType
+ ?? (_responseContentType = GetResponseContentType(Request));
+ set => this._responseContentType = value;
+ }
+
+ public string PathInfo => Request.Path.Value;
+
+ public string UserAgent => Request.Headers[HeaderNames.UserAgent];
+
+ public IHeaderDictionary Headers => Request.Headers;
+
+ public IQueryCollection QueryString => Request.Query;
+
+ public bool IsLocal => Request.HttpContext.Connection.LocalIpAddress.Equals(Request.HttpContext.Connection.RemoteIpAddress);
+
+
+ public string HttpMethod => Request.Method;
+
+ public string Verb => HttpMethod;
+
+ public string ContentType => Request.ContentType;
+
+ public Uri UrlReferrer => Request.GetTypedHeaders().Referer;
+
+ public Stream InputStream => Request.Body;
+
+ public long ContentLength => Request.ContentLength ?? 0;
+
+ private string GetHeader(string name) => Request.Headers[name].ToString();
+
private static IPAddress NormalizeIp(IPAddress ip)
{
if (ip.IsIPv4MappedToIPv6)
@@ -80,22 +116,6 @@ namespace Emby.Server.Implementations.SocketSharp
return ip;
}
- public string[] AcceptTypes => request.Headers.GetCommaSeparatedValues(HeaderNames.Accept);
-
- private Dictionary<string, object> items;
- public Dictionary<string, object> Items => items ?? (items = new Dictionary<string, object>());
-
- private string responseContentType;
- public string ResponseContentType
- {
- get =>
- responseContentType
- ?? (responseContentType = GetResponseContentType(HttpRequest));
- set => this.responseContentType = value;
- }
-
- public const string FormUrlEncoded = "application/x-www-form-urlencoded";
- public const string MultiPartFormData = "multipart/form-data";
public static string GetResponseContentType(HttpRequest httpReq)
{
var specifiedContentType = GetQueryStringContentType(httpReq);
@@ -152,8 +172,6 @@ namespace Emby.Server.Implementations.SocketSharp
return serverDefaultContentType;
}
- public const string Soap11 = "text/xml; charset=utf-8";
-
public static bool HasAnyOfContentTypes(HttpRequest request, params string[] contentTypes)
{
if (contentTypes == null || request.ContentType == null)
@@ -224,105 +242,5 @@ namespace Emby.Server.Implementations.SocketSharp
var pos = strVal.IndexOf(needle);
return pos == -1 ? strVal : strVal.Slice(0, pos);
}
-
- public string PathInfo => this.request.Path.Value;
-
- public string UserAgent => request.Headers[HeaderNames.UserAgent];
-
- public IHeaderDictionary Headers => request.Headers;
-
- public IQueryCollection QueryString => request.Query;
-
- public bool IsLocal => string.Equals(request.HttpContext.Connection.LocalIpAddress.ToString(), request.HttpContext.Connection.RemoteIpAddress.ToString());
-
- private string httpMethod;
- public string HttpMethod =>
- httpMethod
- ?? (httpMethod = request.Method);
-
- public string Verb => HttpMethod;
-
- public string ContentType => request.ContentType;
-
- private Encoding ContentEncoding
- {
- get
- {
- // TODO is this necessary?
- if (UserAgent != null && CultureInfo.InvariantCulture.CompareInfo.IsPrefix(UserAgent, "UP"))
- {
- string postDataCharset = Headers["x-up-devcap-post-charset"];
- if (!string.IsNullOrEmpty(postDataCharset))
- {
- try
- {
- return Encoding.GetEncoding(postDataCharset);
- }
- catch (ArgumentException)
- {
- }
- }
- }
-
- return request.GetTypedHeaders().ContentType.Encoding ?? Encoding.UTF8;
- }
- }
-
- public Uri UrlReferrer => request.GetTypedHeaders().Referer;
-
- public static Encoding GetEncoding(string contentTypeHeader)
- {
- var param = GetParameter(contentTypeHeader.AsSpan(), "charset=");
- if (param == null)
- {
- return null;
- }
-
- try
- {
- return Encoding.GetEncoding(param);
- }
- catch (ArgumentException)
- {
- return null;
- }
- }
-
- public Stream InputStream => request.Body;
-
- public long ContentLength => request.ContentLength ?? 0;
-
- private IHttpFile[] httpFiles;
- public IHttpFile[] Files
- {
- get
- {
- if (httpFiles != null)
- {
- return httpFiles;
- }
-
- if (files == null)
- {
- return httpFiles = Array.Empty<IHttpFile>();
- }
-
- var values = files.Values;
- httpFiles = new IHttpFile[values.Count];
- for (int i = 0; i < values.Count; i++)
- {
- var reqFile = values.ElementAt(i);
- httpFiles[i] = new HttpFile
- {
- ContentType = reqFile.ContentType,
- ContentLength = reqFile.ContentLength,
- FileName = reqFile.FileName,
- InputStream = reqFile.InputStream,
- };
- }
-
- return httpFiles;
- }
- }
}
}
diff --git a/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs
deleted file mode 100644
index 0f67eaa62..000000000
--- a/Emby.Server.Implementations/SocketSharp/WebSocketSharpResponse.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Services;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Logging;
-using IRequest = MediaBrowser.Model.Services.IRequest;
-
-namespace Emby.Server.Implementations.SocketSharp
-{
- public class WebSocketSharpResponse : IResponse
- {
- private readonly ILogger _logger;
-
- public WebSocketSharpResponse(ILogger logger, HttpResponse response)
- {
- _logger = logger;
- OriginalResponse = response;
- }
-
- public HttpResponse OriginalResponse { get; }
-
- public int StatusCode
- {
- get => OriginalResponse.StatusCode;
- set => OriginalResponse.StatusCode = value;
- }
-
- public string StatusDescription { get; set; }
-
- public string ContentType
- {
- get => OriginalResponse.ContentType;
- set => OriginalResponse.ContentType = value;
- }
-
- public void AddHeader(string name, string value)
- {
- if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase))
- {
- ContentType = value;
- return;
- }
-
- OriginalResponse.Headers.Add(name, value);
- }
-
- public void Redirect(string url)
- {
- OriginalResponse.Redirect(url);
- }
-
- public Stream OutputStream => OriginalResponse.Body;
-
- public bool SendChunked { get; set; }
-
- const int StreamCopyToBufferSize = 81920;
- public async Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken)
- {
- var allowAsync = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
-
- //if (count <= 0)
- //{
- // allowAsync = true;
- //}
-
- var fileOpenOptions = FileOpenOptions.SequentialScan;
-
- if (allowAsync)
- {
- fileOpenOptions |= FileOpenOptions.Asynchronous;
- }
-
- // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
-
- using (var fs = fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, fileOpenOptions))
- {
- if (offset > 0)
- {
- fs.Position = offset;
- }
-
- if (count > 0)
- {
- await streamHelper.CopyToAsync(fs, OutputStream, count, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- await fs.CopyToAsync(OutputStream, StreamCopyToBufferSize, cancellationToken).ConfigureAwait(false);
- }
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 630ef4893..4c2f24e6f 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
@@ -73,7 +74,7 @@ namespace Emby.Server.Implementations.TV
{
parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
.Where(i => i is Folder)
- .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N")))
+ .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
.ToArray();
}
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index e7cda2993..185a282ac 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -25,7 +26,7 @@ namespace Emby.Server.Implementations.Udp
private bool _isDisposed;
- private readonly List<Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>> _responders = new List<Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>>();
+ private readonly List<Tuple<string, bool, Func<string, IPEndPoint, Encoding, CancellationToken, Task>>> _responders = new List<Tuple<string, bool, Func<string, IPEndPoint, Encoding, CancellationToken, Task>>>();
private readonly IServerApplicationHost _appHost;
private readonly IJsonSerializer _json;
@@ -43,9 +44,9 @@ namespace Emby.Server.Implementations.Udp
AddMessageResponder("who is JellyfinServer?", true, RespondToV2Message);
}
- private void AddMessageResponder(string message, bool isSubstring, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task> responder)
+ private void AddMessageResponder(string message, bool isSubstring, Func<string, IPEndPoint, Encoding, CancellationToken, Task> responder)
{
- _responders.Add(new Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>(message, isSubstring, responder));
+ _responders.Add(new Tuple<string, bool, Func<string, IPEndPoint, Encoding, CancellationToken, Task>>(message, isSubstring, responder));
}
/// <summary>
@@ -83,7 +84,7 @@ namespace Emby.Server.Implementations.Udp
}
}
- private Tuple<string, Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>> GetResponder(byte[] buffer, int bytesReceived, Encoding encoding)
+ private Tuple<string, Tuple<string, bool, Func<string, IPEndPoint, Encoding, CancellationToken, Task>>> GetResponder(byte[] buffer, int bytesReceived, Encoding encoding)
{
var text = encoding.GetString(buffer, 0, bytesReceived);
var responder = _responders.FirstOrDefault(i =>
@@ -99,10 +100,10 @@ namespace Emby.Server.Implementations.Udp
{
return null;
}
- return new Tuple<string, Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>>(text, responder);
+ return new Tuple<string, Tuple<string, bool, Func<string, IPEndPoint, Encoding, CancellationToken, Task>>>(text, responder);
}
- private async Task RespondToV2Message(string messageText, IpEndPointInfo endpoint, Encoding encoding, CancellationToken cancellationToken)
+ private async Task RespondToV2Message(string messageText, IPEndPoint endpoint, Encoding encoding, CancellationToken cancellationToken)
{
var parts = messageText.Split('|');
@@ -254,7 +255,7 @@ namespace Emby.Server.Implementations.Udp
}
}
- public async Task SendAsync(byte[] bytes, IpEndPointInfo remoteEndPoint, CancellationToken cancellationToken)
+ public async Task SendAsync(byte[] bytes, IPEndPoint remoteEndPoint, CancellationToken cancellationToken)
{
if (_isDisposed)
{