aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/azure-pipelines.yml2
-rw-r--r--.github/ISSUE_TEMPLATE/enhancement-request.md20
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md14
-rw-r--r--.github/stale.yml22
-rw-r--r--CONTRIBUTORS.md1
-rw-r--r--Dockerfile6
-rw-r--r--Dockerfile.arm6
-rw-r--r--Dockerfile.arm646
-rw-r--r--Emby.Dlna/Didl/DidlBuilder.cs34
-rw-r--r--Emby.Dlna/DlnaManager.cs5
-rw-r--r--Emby.Dlna/Eventing/EventManager.cs2
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs6
-rw-r--r--Emby.Dlna/PlayTo/PlayToManager.cs9
-rw-r--r--Emby.Dlna/Profiles/DishHopperJoeyProfile.cs2
-rw-r--r--Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml2
-rw-r--r--Emby.Drawing/ImageProcessor.cs6
-rw-r--r--Emby.Notifications/NotificationManager.cs5
-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
-rw-r--r--Jellyfin.Server/Program.cs13
-rw-r--r--MediaBrowser.Api/Devices/DeviceService.cs15
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs3
-rw-r--r--MediaBrowser.Api/Library/LibraryStructureService.cs3
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs19
-rw-r--r--MediaBrowser.Api/Movies/MoviesService.cs6
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs4
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs3
-rw-r--r--MediaBrowser.Api/SearchService.cs5
-rw-r--r--MediaBrowser.Api/Session/SessionsService.cs3
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs4
-rw-r--r--MediaBrowser.Api/TvShowsService.cs3
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs6
-rw-r--r--MediaBrowser.Api/UserLibrary/UserViewsService.cs3
-rw-r--r--MediaBrowser.Api/VideosService.cs3
-rw-r--r--MediaBrowser.Common/Net/INetworkManager.cs18
-rw-r--r--MediaBrowser.Controller/Authentication/AuthenticationException.cs28
-rw-r--r--MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs3
-rw-r--r--MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs1
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs7
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs14
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs5
-rw-r--r--MediaBrowser.Controller/Entities/LinkedChild.cs5
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs3
-rw-r--r--MediaBrowser.Controller/Entities/User.cs3
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs3
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs8
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs4
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvProgram.cs3
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs8
-rw-r--r--MediaBrowser.Controller/Net/AuthenticatedAttribute.cs3
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs3
-rw-r--r--MediaBrowser.Controller/Providers/MetadataResult.cs3
-rw-r--r--MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs6
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs8
-rw-r--r--MediaBrowser.Model/Cryptography/ICryptoProvider.cs6
-rw-r--r--MediaBrowser.Model/Cryptography/PasswordHash.cs152
-rw-r--r--MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs4
-rw-r--r--MediaBrowser.Model/Net/ISocket.cs5
-rw-r--r--MediaBrowser.Model/Net/ISocketFactory.cs11
-rw-r--r--MediaBrowser.Model/Net/IpAddressInfo.cs38
-rw-r--r--MediaBrowser.Model/Net/IpEndPointInfo.cs29
-rw-r--r--MediaBrowser.Model/Net/MimeTypes.cs376
-rw-r--r--MediaBrowser.Model/Net/SocketReceiveResult.cs6
-rw-r--r--MediaBrowser.Model/Services/IHasRequestFilter.cs4
-rw-r--r--MediaBrowser.Model/Services/IRequest.cs38
-rw-r--r--MediaBrowser.Model/System/WakeOnLanInfo.cs37
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs8
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs7
-rw-r--r--MediaBrowser.Providers/Subtitles/SubtitleManager.cs5
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs17
-rw-r--r--MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs5
-rw-r--r--README.md7
-rw-r--r--RSSDP/DeviceAvailableEventArgs.cs53
-rw-r--r--RSSDP/ISsdpCommunicationsServer.cs8
-rw-r--r--RSSDP/RequestReceivedEventArgs.cs12
-rw-r--r--RSSDP/ResponseReceivedEventArgs.cs12
-rw-r--r--RSSDP/SsdpCommunicationsServer.cs52
-rw-r--r--RSSDP/SsdpDevice.cs3
-rw-r--r--RSSDP/SsdpDeviceLocator.cs17
-rw-r--r--RSSDP/SsdpDevicePublisher.cs32
-rw-r--r--RSSDP/SsdpRootDevice.cs10
-rw-r--r--jellyfin.ruleset4
160 files changed, 1644 insertions, 5215 deletions
diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml
index efd69680e..46db0d9fe 100644
--- a/.ci/azure-pipelines.yml
+++ b/.ci/azure-pipelines.yml
@@ -190,7 +190,7 @@ jobs:
- task: CmdLine@2
displayName: Execute ABI compatibility check tool
inputs:
- script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName)'
+ script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines'
workingDirectory: $(System.ArtifactsDirectory) # Optional
#failOnStderr: false # Optional
diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md
deleted file mode 100644
index a655b60f5..000000000
--- a/.github/ISSUE_TEMPLATE/enhancement-request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Enhancement request
-about: Suggest an modification to an existing feature
-title: ''
-labels: enhancement
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
-
-**Describe the solution you'd like**
-<!-- A clear and concise description of what you want to happen. -->
-
-**Describe alternatives you've considered**
-<!-- A clear and concise description of any alternative solutions or features you've considered. -->
-
-**Additional context**
-<!-- Add any other context or screenshots about the feature request here. -->
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 3cbc8cbb9..000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-name: Feature request
-about: Suggest a new feature
-title: ''
-labels: feature
-assignees: ''
-
----
-
-**Describe the feature you'd like**
-<!-- A clear and concise description of what you want to happen. -->
-
-**Additional context**
-<!-- Add any other context or screenshots about the feature request here. -->
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000..ce9fb01a1
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,22 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 90
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 14
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - regression
+ - security
+ - dotnet-3.0-future
+ - roadmap
+ - future
+ - feature
+ - enhancement
+# Label to use when marking an issue as stale
+staleLabel: stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ Issues go stale after 90d of inactivity. Mark the issue as fresh by adding a comment or commit. Stale issues close after an additional 14d of inactivity.
+ If this issue is safe to close now please do so.
+ If you have any questions you can reach us on [Matrix or Social Media](https://jellyfin.readthedocs.io/en/latest/getting-help/).
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 9168dccc8..c96228f31 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -27,6 +27,7 @@
- [pjeanjean](https://github.com/pjeanjean)
- [DrPandemic](https://github.com/drpandemic)
- [joern-h](https://github.com/joern-h)
+ - [Khinenw](https://github.com/HelloWorld017)
# Emby Contributors
diff --git a/Dockerfile b/Dockerfile
index 057d4b041..f8e6fec31 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,10 +21,10 @@ RUN apt-get update \
COPY --from=ffmpeg / /
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.7
-RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
+ARG JELLYFIN_WEB_VERSION=v10.3.7
+RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
- && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+ && mv jellyfin-web-* /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
diff --git a/Dockerfile.arm b/Dockerfile.arm
index dad4da1f1..651bdeff4 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -26,10 +26,10 @@ RUN apt-get update \
&& chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.7
-RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
+ARG JELLYFIN_WEB_VERSION=v10.3.7
+RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
- && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+ && mv jellyfin-web-* /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 5d4e86bff..f6bd81e4c 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -26,10 +26,10 @@ RUN apt-get update \
&& chmod 777 /cache /config /media
COPY --from=builder /jellyfin /jellyfin
-ARG JELLYFIN_WEB_VERSION=10.3.7
-RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/v${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
+ARG JELLYFIN_WEB_VERSION=v10.3.7
+RUN curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
&& rm -rf /jellyfin/jellyfin-web \
- && mv jellyfin-web-${JELLYFIN_WEB_VERSION} /jellyfin/jellyfin-web
+ && mv jellyfin-web-* /jellyfin/jellyfin-web
EXPOSE 8096
VOLUME /cache /config /media
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index 992a50e67..26adfde83 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -181,19 +181,6 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement();
}
- private string GetMimeType(string input)
- {
- var mime = MimeTypes.GetMimeType(input);
-
- // TODO: Instead of being hard-coded here, this should probably be moved into all of the existing profiles
- if (string.Equals(mime, "video/mp2t", StringComparison.OrdinalIgnoreCase))
- {
- mime = "video/mpeg";
- }
-
- return mime;
- }
-
private void AddVideoResource(DlnaOptions options, XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
{
if (streamInfo == null)
@@ -384,7 +371,7 @@ namespace Emby.Dlna.Didl
var filename = url.Substring(0, url.IndexOf('?'));
var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
- ? GetMimeType(filename)
+ ? MimeTypes.GetMimeType(filename)
: mediaProfile.MimeType;
writer.WriteAttributeString("protocolInfo", string.Format(
@@ -520,7 +507,7 @@ namespace Emby.Dlna.Didl
var filename = url.Substring(0, url.IndexOf('?'));
var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
- ? GetMimeType(filename)
+ ? MimeTypes.GetMimeType(filename)
: mediaProfile.MimeType;
var contentFeatures = new ContentFeatureBuilder(_profile).BuildAudioHeader(streamInfo.Container,
@@ -545,17 +532,10 @@ namespace Emby.Dlna.Didl
}
public static bool IsIdRoot(string id)
- {
- if (string.IsNullOrWhiteSpace(id)
+ => string.IsNullOrWhiteSpace(id)
|| string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
// Samsung sometimes uses 1 as root
- || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
-
- return false;
- }
+ || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase);
public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string requestedId = null)
{
@@ -971,7 +951,7 @@ namespace Emby.Dlna.Didl
writer.WriteAttributeString("protocolInfo", string.Format(
"http-get:*:{0}:{1}",
- GetMimeType("file." + format),
+ MimeTypes.GetMimeType("file." + format),
contentFeatures
));
@@ -1102,7 +1082,7 @@ namespace Emby.Dlna.Didl
public static string GetClientId(Guid idValue, StubType? stubType)
{
- var id = idValue.ToString("N");
+ var id = idValue.ToString("N", CultureInfo.InvariantCulture);
if (stubType.HasValue)
{
@@ -1116,7 +1096,7 @@ namespace Emby.Dlna.Didl
{
var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/0/0",
_serverAddress,
- info.ItemId.ToString("N"),
+ info.ItemId.ToString("N", CultureInfo.InvariantCulture),
info.Type,
info.ImageTag,
format,
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 2b76d2702..d5d788021 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -300,7 +301,7 @@ namespace Emby.Dlna
profile = ReserializeProfile(tempProfile);
- profile.Id = path.ToLowerInvariant().GetMD5().ToString("N");
+ profile.Id = path.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
_profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile);
@@ -352,7 +353,7 @@ namespace Emby.Dlna
Info = new DeviceProfileInfo
{
- Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N"),
+ Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture),
Name = _fileSystem.GetFileNameWithoutExtension(file),
Type = type
}
diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs
index b4ff3ec1d..4b542a820 100644
--- a/Emby.Dlna/Eventing/EventManager.cs
+++ b/Emby.Dlna/Eventing/EventManager.cs
@@ -55,7 +55,7 @@ namespace Emby.Dlna.Eventing
public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl)
{
var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
- var id = "uuid:" + Guid.NewGuid().ToString("N");
+ var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
// Remove logging for now because some devices are sending this very frequently
// TODO re-enable with dlna debug logging setting
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 5fbe70ded..77bde0ca2 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -1,4 +1,6 @@
using System;
+using System.Net.Sockets;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Emby.Dlna.PlayTo;
@@ -247,7 +249,7 @@ namespace Emby.Dlna.Main
foreach (var address in addresses)
{
- if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
// Not support IPv6 right now
continue;
@@ -306,7 +308,7 @@ namespace Emby.Dlna.Main
{
guid = text.GetMD5();
}
- return guid.ToString("N");
+ return guid.ToString("N", CultureInfo.InvariantCulture);
}
private void SetProperies(SsdpDevice device, string fullDeviceType)
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 28e70d046..a3a013096 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -1,5 +1,7 @@
using System;
+using System.Globalization;
using System.Linq;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
@@ -14,7 +16,6 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using Microsoft.Extensions.Logging;
@@ -141,7 +142,7 @@ namespace Emby.Dlna.PlayTo
return usn;
}
- return usn.GetMD5().ToString("N");
+ return usn.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
private async Task AddDevice(UpnpDeviceInfo info, string location, CancellationToken cancellationToken)
@@ -156,7 +157,7 @@ namespace Emby.Dlna.PlayTo
}
else
{
- uuid = location.GetMD5().ToString("N");
+ uuid = location.GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersion, uuid, null, uri.OriginalString, null);
@@ -172,7 +173,7 @@ namespace Emby.Dlna.PlayTo
_sessionManager.UpdateDeviceName(sessionInfo.Id, deviceName);
string serverAddress;
- if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IpAddressInfo.Any) || info.LocalIpAddress.Equals(IpAddressInfo.IPv6Any))
+ if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IPAddress.Any) || info.LocalIpAddress.Equals(IPAddress.IPv6Any))
{
serverAddress = await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
}
diff --git a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
index d501cce0d..8d8ab41ca 100644
--- a/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
+++ b/Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
@@ -9,7 +9,7 @@ namespace Emby.Dlna.Profiles
{
Name = "Dish Hopper-Joey";
- ProtocolInfo = "http-get:*:video/mp2t:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*";
+ ProtocolInfo = "http-get:*:video/mp2t:*,http-get:*:video/mpeg:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*";
Identification = new DeviceIdentification
{
diff --git a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
index 5ff497560..5b299577e 100644
--- a/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
+++ b/Emby.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
@@ -28,7 +28,7 @@
<MaxStaticBitrate>140000000</MaxStaticBitrate>
<MusicStreamingTranscodingBitrate>192000</MusicStreamingTranscodingBitrate>
<MaxStaticMusicBitrate xsi:nil="true" />
- <ProtocolInfo>http-get:*:video/mp2t:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*</ProtocolInfo>
+ <ProtocolInfo>http-get:*:video/mp2t:http-get:*:video/mpeg:*,http-get:*:video/MP1S:*,http-get:*:video/mpeg2:*,http-get:*:video/mp4:*,http-get:*:video/x-matroska:*,http-get:*:audio/mpeg:*,http-get:*:audio/mpeg3:*,http-get:*:audio/mp3:*,http-get:*:audio/mp4:*,http-get:*:audio/mp4a-latm:*,http-get:*:image/jpeg:*</ProtocolInfo>
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
<RequiresPlainFolders>false</RequiresPlainFolders>
diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs
index 6d209d8d0..a7d95eb20 100644
--- a/Emby.Drawing/ImageProcessor.cs
+++ b/Emby.Drawing/ImageProcessor.cs
@@ -454,14 +454,14 @@ namespace Emby.Drawing
// Optimization
if (imageEnhancers.Length == 0)
{
- return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N");
+ return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
// Cache name is created with supported enhancers combined with the last config change so we pick up new config changes
var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
cacheKeys.Add(originalImagePath + dateModified.Ticks);
- return string.Join("|", cacheKeys).GetMD5().ToString("N");
+ return string.Join("|", cacheKeys).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
@@ -480,7 +480,7 @@ namespace Emby.Drawing
{
try
{
- string filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N");
+ string filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N", CultureInfo.InvariantCulture);
string cacheExtension = _mediaEncoder().SupportsEncoder("libwebp") ? ".webp" : ".png";
var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + cacheExtension);
diff --git a/Emby.Notifications/NotificationManager.cs b/Emby.Notifications/NotificationManager.cs
index 3d1d4722d..a767e541e 100644
--- a/Emby.Notifications/NotificationManager.cs
+++ b/Emby.Notifications/NotificationManager.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.Notifications
var config = GetConfiguration();
return _userManager.Users
- .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Policy))
+ .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N", CultureInfo.InvariantCulture), i.Policy))
.Select(i => i.Id);
}
@@ -197,7 +198,7 @@ namespace Emby.Notifications
return _services.Select(i => new NameIdPair
{
Name = i.Name,
- Id = i.Name.GetMD5().ToString("N")
+ Id = i.Name.GetMD5().ToString("N", CultureInfo.InvariantCulture)
}).OrderBy(i => i.Name);
}
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)
{
diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs
index 94308a98e..952990493 100644
--- a/Jellyfin.Server/Program.cs
+++ b/Jellyfin.Server/Program.cs
@@ -18,7 +18,6 @@ using Jellyfin.Drawing.Skia;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -41,12 +40,12 @@ namespace Jellyfin.Server
// For backwards compatibility.
// Modify any input arguments now which start with single-hyphen to POSIX standard
// double-hyphen to allow parsing by CommandLineParser package.
- const string pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx
- const string substitution = @"-$1"; // Prepend with additional single-hyphen
- var regex = new Regex(pattern);
+ const string Pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx
+ const string Substitution = @"-$1"; // Prepend with additional single-hyphen
+ var regex = new Regex(Pattern);
for (var i = 0; i < args.Length; i++)
{
- args[i] = regex.Replace(args[i], substitution);
+ args[i] = regex.Replace(args[i], Substitution);
}
// Parse the command line arguments and either start the app or exit indicating error
@@ -134,7 +133,7 @@ namespace Jellyfin.Server
Batteries_V2.Init();
if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK)
{
- Console.WriteLine("WARN: Failed to enable shared cache for SQLite");
+ _logger.LogWarning("Failed to enable shared cache for SQLite");
}
using (var appHost = new CoreAppHost(
@@ -143,7 +142,7 @@ namespace Jellyfin.Server
options,
new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
new NullImageEncoder(),
- new NetworkManager(_loggerFactory),
+ new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()),
appConfig))
{
await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs
index dc211af6b..697a84f5c 100644
--- a/MediaBrowser.Api/Devices/DeviceService.cs
+++ b/MediaBrowser.Api/Devices/DeviceService.cs
@@ -133,12 +133,15 @@ namespace MediaBrowser.Api.Devices
var album = Request.QueryString["Album"];
var id = Request.QueryString["Id"];
var name = Request.QueryString["Name"];
+ var req = Request.Response.HttpContext.Request;
- if (Request.ContentType.IndexOf("multi", StringComparison.OrdinalIgnoreCase) == -1)
+ if (req.HasFormContentType)
{
- return _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo
+ var file = req.Form.Files.Count == 0 ? null : req.Form.Files[0];
+
+ return _deviceManager.AcceptCameraUpload(deviceId, file.OpenReadStream(), new LocalFileInfo
{
- MimeType = Request.ContentType,
+ MimeType = file.ContentType,
Album = album,
Name = name,
Id = id
@@ -146,11 +149,9 @@ namespace MediaBrowser.Api.Devices
}
else
{
- var file = Request.Files.Length == 0 ? null : Request.Files[0];
-
- return _deviceManager.AcceptCameraUpload(deviceId, file.InputStream, new LocalFileInfo
+ return _deviceManager.AcceptCameraUpload(deviceId, request.RequestStream, new LocalFileInfo
{
- MimeType = file.ContentType,
+ MimeType = Request.ContentType,
Album = album,
Name = name,
Id = id
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 10bbc9e5d..23c7339d2 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -537,7 +538,7 @@ namespace MediaBrowser.Api.Images
if (item == null)
{
- throw new ResourceNotFoundException(string.Format("Item {0} not found.", itemId.ToString("N")));
+ throw new ResourceNotFoundException(string.Format("Item {0} not found.", itemId.ToString("N", CultureInfo.InvariantCulture)));
}
}
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index d6bcf7878..7266bf9f9 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -272,7 +273,7 @@ namespace MediaBrowser.Api.Library
// Changing capitalization. Handle windows case insensitivity
if (string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase))
{
- var tempPath = Path.Combine(rootFolderPath, Guid.NewGuid().ToString("N"));
+ var tempPath = Path.Combine(rootFolderPath, Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture));
Directory.Move(currentPath, tempPath);
currentPath = tempPath;
}
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index e41ad540a..8a4d6e216 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -599,7 +599,6 @@ namespace MediaBrowser.Api.LiveTv
{
public bool ValidateLogin { get; set; }
public bool ValidateListings { get; set; }
- public string Pw { get; set; }
}
[Route("/LiveTv/ListingProviders", "DELETE", Summary = "Deletes a listing provider")]
@@ -867,28 +866,10 @@ namespace MediaBrowser.Api.LiveTv
public async Task<object> Post(AddListingProvider request)
{
- if (request.Pw != null)
- {
- request.Password = GetHashedString(request.Pw);
- }
-
- request.Pw = null;
-
var result = await _liveTvManager.SaveListingProvider(request, request.ValidateLogin, request.ValidateListings).ConfigureAwait(false);
return ToOptimizedResult(result);
}
- /// <summary>
- /// Gets the hashed string.
- /// </summary>
- private string GetHashedString(string str)
- {
- // legacy
- return BitConverter.ToString(
- _cryptographyProvider.ComputeSHA1(Encoding.UTF8.GetBytes(str)))
- .Replace("-", string.Empty).ToLowerInvariant();
- }
-
public void Delete(DeleteListingProvider request)
{
_liveTvManager.DeleteListingsProvider(request.Id);
diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs
index 91766255f..d601fb500 100644
--- a/MediaBrowser.Api/Movies/MoviesService.cs
+++ b/MediaBrowser.Api/Movies/MoviesService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
@@ -11,7 +12,6 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Services;
@@ -268,7 +268,7 @@ namespace MediaBrowser.Api.Movies
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
- }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture))
.Select(x => x.First())
.Take(itemLimit)
.ToList();
@@ -309,7 +309,7 @@ namespace MediaBrowser.Api.Movies
EnableGroupByMetadataKey = true,
DtoOptions = dtoOptions
- }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
+ }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture))
.Select(x => x.First())
.Take(itemLimit)
.ToList();
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 4a198661c..1f78f5afc 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -142,7 +142,7 @@ namespace MediaBrowser.Api.Playback
data += "-" + (state.Request.DeviceId ?? string.Empty)
+ "-" + (state.Request.PlaySessionId ?? string.Empty);
- var filename = data.GetMD5().ToString("N");
+ var filename = data.GetMD5().ToString("N", CultureInfo.InvariantCulture);
var ext = outputFileExtension.ToLowerInvariant();
var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath;
@@ -240,7 +240,7 @@ namespace MediaBrowser.Api.Playback
var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
state.Request.PlaySessionId,
state.MediaSource.LiveStreamId,
- Guid.NewGuid().ToString("N"),
+ Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
TranscodingJobType,
process,
state.Request.DeviceId,
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index ab3994a63..da8f99a3d 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -306,7 +307,7 @@ namespace MediaBrowser.Api.Playback
{
result.MediaSources = Clone(result.MediaSources);
- result.PlaySessionId = Guid.NewGuid().ToString("N");
+ result.PlaySessionId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
return result;
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs
index ecf07c912..6c67d4fb1 100644
--- a/MediaBrowser.Api/SearchService.cs
+++ b/MediaBrowser.Api/SearchService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@@ -305,7 +306,7 @@ namespace MediaBrowser.Api
if (tag != null)
{
hint.ThumbImageTag = tag;
- hint.ThumbImageItemId = itemWithImage.Id.ToString("N");
+ hint.ThumbImageItemId = itemWithImage.Id.ToString("N", CultureInfo.InvariantCulture);
}
}
}
@@ -326,7 +327,7 @@ namespace MediaBrowser.Api
if (tag != null)
{
hint.BackdropImageTag = tag;
- hint.BackdropImageItemId = itemWithImage.Id.ToString("N");
+ hint.BackdropImageItemId = itemWithImage.Id.ToString("N", CultureInfo.InvariantCulture);
}
}
}
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index 4109b12bf..76392e27c 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -316,7 +317,7 @@ namespace MediaBrowser.Api.Session
_authRepo.Create(new AuthenticationInfo
{
AppName = request.App,
- AccessToken = Guid.NewGuid().ToString("N"),
+ AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
DateCreated = DateTime.UtcNow,
DeviceId = _appHost.SystemId,
DeviceName = _appHost.FriendlyName,
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 08aa540a5..52043d3df 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -168,7 +168,7 @@ namespace MediaBrowser.Api.Subtitles
builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
builder.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
- long positionTicks = 0;
+ long positionTicks = 0;
var accessToken = _authContext.GetAuthorizationInfo(Request).Token;
@@ -206,7 +206,7 @@ namespace MediaBrowser.Api.Subtitles
{
var item = (Video)_libraryManager.GetItemById(request.Id);
- var idString = request.Id.ToString("N");
+ var idString = request.Id.ToString("N", CultureInfo.InvariantCulture);
var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null)
.First(i => string.Equals(i.Id, request.MediaSourceId ?? idString));
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index b0900a554..2951fa6b4 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Dto;
@@ -470,7 +471,7 @@ namespace MediaBrowser.Api
if (!string.IsNullOrWhiteSpace(request.StartItemId))
{
- episodes = episodes.SkipWhile(i => !string.Equals(i.Id.ToString("N"), request.StartItemId, StringComparison.OrdinalIgnoreCase)).ToList();
+ episodes = episodes.SkipWhile(i => !string.Equals(i.Id.ToString("N", CultureInfo.InvariantCulture), request.StartItemId, StringComparison.OrdinalIgnoreCase)).ToList();
}
// This must be the last filter
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index f842230ee..a1e976bed 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -99,7 +99,7 @@ namespace MediaBrowser.Api.UserLibrary
{
ancestorIds = _libraryManager.GetUserRootFolder().GetChildren(user, true)
.Where(i => i is Folder)
- .Where(i => !excludeFolderIds.Contains(i.Id.ToString("N")))
+ .Where(i => !excludeFolderIds.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
.Select(i => i.Id)
.ToArray();
}
@@ -228,7 +228,9 @@ namespace MediaBrowser.Api.UserLibrary
var collectionFolders = _libraryManager.GetCollectionFolders(item);
foreach (var collectionFolder in collectionFolders)
{
- if (user.Policy.EnabledFolders.Contains(collectionFolder.Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (user.Policy.EnabledFolders.Contains(
+ collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),
+ StringComparer.OrdinalIgnoreCase))
{
isInEnabledFolder = true;
}
diff --git a/MediaBrowser.Api/UserLibrary/UserViewsService.cs b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
index 1d61c5c1e..2fa5d8933 100644
--- a/MediaBrowser.Api/UserLibrary/UserViewsService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserViewsService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -116,7 +117,7 @@ namespace MediaBrowser.Api.UserLibrary
.Select(i => new SpecialViewOption
{
Name = i.Name,
- Id = i.Id.ToString("N")
+ Id = i.Id.ToString("N", CultureInfo.InvariantCulture)
})
.OrderBy(i => i.Name)
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index 061f72438..474036f5c 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Controller.Configuration;
@@ -168,7 +169,7 @@ namespace MediaBrowser.Api
foreach (var item in items.Where(i => i.Id != primaryVersion.Id))
{
- item.SetPrimaryVersionId(primaryVersion.Id.ToString("N"));
+ item.SetPrimaryVersionId(primaryVersion.Id.ToString("N", CultureInfo.InvariantCulture));
item.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None);
diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs
index 34c6f5866..1df74d995 100644
--- a/MediaBrowser.Common/Net/INetworkManager.cs
+++ b/MediaBrowser.Common/Net/INetworkManager.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Threading.Tasks;
+using System.Net;
+using System.Net.NetworkInformation;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
@@ -24,7 +25,7 @@ namespace MediaBrowser.Common.Net
/// Returns MAC Address from first Network Card in Computer
/// </summary>
/// <returns>[string] MAC Address</returns>
- List<string> GetMacAddresses();
+ List<PhysicalAddress> GetMacAddresses();
/// <summary>
/// Determines whether [is in private address space] [the specified endpoint].
@@ -53,17 +54,12 @@ namespace MediaBrowser.Common.Net
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
bool IsInLocalNetwork(string endpoint);
- IpAddressInfo[] GetLocalIpAddresses(bool ignoreVirtualInterface);
-
- IpAddressInfo ParseIpAddress(string ipAddress);
-
- bool TryParseIpAddress(string ipAddress, out IpAddressInfo ipAddressInfo);
-
- Task<IpAddressInfo[]> GetHostAddressesAsync(string host);
+ IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface);
bool IsAddressInSubnets(string addressString, string[] subnets);
- bool IsInSameSubnet(IpAddressInfo address1, IpAddressInfo address2, IpAddressInfo subnetMask);
- IpAddressInfo GetLocalIpSubnetMask(IpAddressInfo address);
+ bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask);
+
+ IPAddress GetLocalIpSubnetMask(IPAddress address);
}
}
diff --git a/MediaBrowser.Controller/Authentication/AuthenticationException.cs b/MediaBrowser.Controller/Authentication/AuthenticationException.cs
new file mode 100644
index 000000000..045cbcdae
--- /dev/null
+++ b/MediaBrowser.Controller/Authentication/AuthenticationException.cs
@@ -0,0 +1,28 @@
+using System;
+namespace MediaBrowser.Controller.Authentication
+{
+ /// <summary>
+ /// The exception that is thrown when an attempt to authenticate fails.
+ /// </summary>
+ public class AuthenticationException : Exception
+ {
+ /// <inheritdoc />
+ public AuthenticationException() : base()
+ {
+
+ }
+
+ /// <inheritdoc />
+ public AuthenticationException(string message) : base(message)
+ {
+
+ }
+
+ /// <inheritdoc />
+ public AuthenticationException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
index 2cf531eed..f5571065f 100644
--- a/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
+++ b/MediaBrowser.Controller/Authentication/IAuthenticationProvider.cs
@@ -9,10 +9,9 @@ namespace MediaBrowser.Controller.Authentication
string Name { get; }
bool IsEnabled { get; }
Task<ProviderAuthenticationResult> Authenticate(string username, string password);
- Task<bool> HasPassword(User user);
+ bool HasPassword(User user);
Task ChangePassword(User user, string newPassword);
void ChangeEasyPassword(User user, string newPassword, string newPasswordHash);
- string GetPasswordHash(User user);
string GetEasyPasswordHash(User user);
}
diff --git a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
index 9e5cd8816..2639960e7 100644
--- a/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
+++ b/MediaBrowser.Controller/Authentication/IPasswordResetProvider.cs
@@ -12,6 +12,7 @@ namespace MediaBrowser.Controller.Authentication
Task<ForgotPasswordResult> StartForgotPasswordProcess(User user, bool isInNetwork);
Task<PinRedeemResult> RedeemPasswordResetPin(string pin);
}
+
public class PasswordPinCreationResult
{
public string PinFile { get; set; }
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index adf03fb66..89159973b 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.Linq;
using System.Threading;
using MediaBrowser.Common.Progress;
@@ -14,14 +15,14 @@ namespace MediaBrowser.Controller.Channels
{
if (user.Policy.BlockedChannels != null)
{
- if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (user.Policy.BlockedChannels.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return false;
}
}
else
{
- if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return false;
}
@@ -60,7 +61,7 @@ namespace MediaBrowser.Controller.Channels
public static string GetInternalMetadataPath(string basePath, Guid id)
{
- return System.IO.Path.Combine(basePath, "channels", id.ToString("N"), "metadata");
+ return System.IO.Path.Combine(basePath, "channels", id.ToString("N", CultureInfo.InvariantCulture), "metadata");
}
public override bool CanDelete()
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 10a603e42..2ae856b02 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -503,7 +503,7 @@ namespace MediaBrowser.Controller.Entities
foreach (var folder in collectionFolders)
{
- if (allowed.Contains(folder.Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (allowed.Contains(folder.Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return true;
}
@@ -664,10 +664,10 @@ namespace MediaBrowser.Controller.Entities
{
if (SourceType == SourceType.Channel)
{
- return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N"), Id.ToString("N"));
+ return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture));
}
- var idString = Id.ToString("N");
+ var idString = Id.ToString("N", CultureInfo.InvariantCulture);
basePath = System.IO.Path.Combine(basePath, "library");
@@ -1095,7 +1095,7 @@ namespace MediaBrowser.Controller.Entities
var info = new MediaSourceInfo
{
- Id = item.Id.ToString("N"),
+ Id = item.Id.ToString("N", CultureInfo.InvariantCulture),
Protocol = protocol ?? MediaProtocol.File,
MediaStreams = MediaSourceManager.GetMediaStreams(item.Id),
Name = GetMediaSourceName(item),
@@ -1113,7 +1113,7 @@ namespace MediaBrowser.Controller.Entities
if (info.Protocol == MediaProtocol.File)
{
- info.ETag = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N");
+ info.ETag = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
var video = item as Video;
@@ -1626,7 +1626,7 @@ namespace MediaBrowser.Controller.Entities
public virtual string CreatePresentationUniqueKey()
{
- return Id.ToString("N");
+ return Id.ToString("N", CultureInfo.InvariantCulture);
}
[IgnoreDataMember]
@@ -2736,7 +2736,7 @@ namespace MediaBrowser.Controller.Entities
{
var list = GetEtagValues(user);
- return string.Join("|", list.ToArray()).GetMD5().ToString("N");
+ return string.Join("|", list.ToArray()).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
protected virtual List<string> GetEtagValues(User user)
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index c056bc0b4..d841b7ef8 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -177,7 +178,7 @@ namespace MediaBrowser.Controller.Entities
{
if (user.Policy.BlockedMediaFolders != null)
{
- if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) ||
+ if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) ||
// Backwards compatibility
user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
@@ -187,7 +188,7 @@ namespace MediaBrowser.Controller.Entities
}
else
{
- if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+ if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
{
return false;
}
diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs
index bb2d03246..823060488 100644
--- a/MediaBrowser.Controller/Entities/LinkedChild.cs
+++ b/MediaBrowser.Controller/Entities/LinkedChild.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -29,7 +30,7 @@ namespace MediaBrowser.Controller.Entities
if (string.IsNullOrEmpty(child.Path))
{
- child.LibraryItemId = item.Id.ToString("N");
+ child.LibraryItemId = item.Id.ToString("N", CultureInfo.InvariantCulture);
}
return child;
@@ -37,7 +38,7 @@ namespace MediaBrowser.Controller.Entities
public LinkedChild()
{
- Id = Guid.NewGuid().ToString("N");
+ Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
}
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index eae834f6f..1aacc13c9 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -91,7 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
var folders = LibraryManager.GetCollectionFolders(this)
- .Select(i => i.Id.ToString("N"))
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
.ToArray();
if (folders.Length == 0)
diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs
index 9952ba418..968d72579 100644
--- a/MediaBrowser.Controller/Entities/User.cs
+++ b/MediaBrowser.Controller/Entities/User.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -230,7 +231,7 @@ namespace MediaBrowser.Controller.Entities
// TODO: Remove idPath and just use usernamePath for future releases
var usernamePath = System.IO.Path.Combine(parentPath, username);
- var idPath = System.IO.Path.Combine(parentPath, Id.ToString("N"));
+ var idPath = System.IO.Path.Combine(parentPath, Id.ToString("N", CultureInfo.InvariantCulture));
if (!Directory.Exists(usernamePath) && Directory.Exists(idPath))
{
Directory.Move(idPath, usernamePath);
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index e483c8f34..454bdc4ae 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.Movies;
@@ -987,7 +988,7 @@ namespace MediaBrowser.Controller.Entities
private UserView GetUserViewWithName(string name, string type, string sortName, BaseItem parent)
{
- return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N"), type, sortName);
+ return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N", CultureInfo.InvariantCulture), type, sortName);
}
private UserView GetUserView(string type, string localizationKey, string sortName, BaseItem parent)
diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs
index 81b9ff0a5..61b2c15ae 100644
--- a/MediaBrowser.Controller/IServerApplicationHost.cs
+++ b/MediaBrowser.Controller/IServerApplicationHost.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.System;
namespace MediaBrowser.Controller
@@ -59,7 +59,7 @@ namespace MediaBrowser.Controller
/// Gets the local ip address.
/// </summary>
/// <value>The local ip address.</value>
- Task<List<IpAddressInfo>> GetLocalIpAddresses(CancellationToken cancellationToken);
+ Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken);
/// <summary>
/// Gets the local API URL.
@@ -77,13 +77,13 @@ namespace MediaBrowser.Controller
/// <summary>
/// Gets the local API URL.
/// </summary>
- string GetLocalApiUrl(IpAddressInfo address);
+ string GetLocalApiUrl(IPAddress address);
void LaunchUrl(string url);
void EnableLoopback(string appName);
- WakeOnLanInfo[] GetWakeOnLanInfo();
+ IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
string ExpandVirtualPath(string path);
string ReverseVirtualPath(string path);
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index 55f47aae9..351662b29 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -89,7 +89,7 @@ namespace MediaBrowser.Controller.LiveTv
var info = new MediaSourceInfo
{
- Id = Id.ToString("N"),
+ Id = Id.ToString("N", CultureInfo.InvariantCulture),
Protocol = PathProtocol ?? MediaProtocol.File,
MediaStreams = new List<MediaStream>(),
Name = Name,
@@ -111,7 +111,7 @@ namespace MediaBrowser.Controller.LiveTv
protected override string GetInternalMetadataPath(string basePath)
{
- return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"), "metadata");
+ return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N", CultureInfo.InvariantCulture), "metadata");
}
public override bool CanDelete()
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index 8bde6a5da..bdaf10d00 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
@@ -188,7 +189,7 @@ namespace MediaBrowser.Controller.LiveTv
protected override string GetInternalMetadataPath(string basePath)
{
- return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N"));
+ return System.IO.Path.Combine(basePath, "livetv", Id.ToString("N", CultureInfo.InvariantCulture));
}
public override bool CanDelete()
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 2984efec3..b9ccc93ef 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -573,7 +573,9 @@ namespace MediaBrowser.Controller.MediaEncoding
}
// TODO: Perhaps also use original_size=1920x800 ??
- return string.Format("subtitles=filename='{0}'{1}{2}{3}",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "subtitles=filename='{0}'{1}{2}",
_mediaEncoder.EscapeSubtitleFilterPath(subtitlePath),
charsetParam,
// fallbackFontParam,
@@ -582,7 +584,9 @@ namespace MediaBrowser.Controller.MediaEncoding
var mediaPath = state.MediaPath ?? string.Empty;
- return string.Format("subtitles='{0}:si={1}'{2}",
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "subtitles='{0}:si={1}'{2}",
_mediaEncoder.EscapeSubtitleFilterPath(mediaPath),
state.InternalSubtitleStreamOffset.ToString(_usCulture),
// fallbackFontParam,
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
index 64c2294e3..29fb81e32 100644
--- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
+++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
@@ -1,5 +1,6 @@
using System;
using MediaBrowser.Model.Services;
+using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
{
@@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="request">The http request wrapper</param>
/// <param name="response">The http response wrapper</param>
/// <param name="requestDto">The request DTO</param>
- public void RequestFilter(IRequest request, IResponse response, object requestDto)
+ public void RequestFilter(IRequest request, HttpResponse response, object requestDto)
{
AuthService.Authenticate(request, this);
}
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index e83260725..aff687f88 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -239,7 +240,7 @@ namespace MediaBrowser.Controller.Playlists
return base.IsVisible(user);
}
- var userId = user.Id.ToString("N");
+ var userId = user.Id.ToString("N", CultureInfo.InvariantCulture);
foreach (var share in shares)
{
if (string.Equals(share.UserId, userId, StringComparison.OrdinalIgnoreCase))
diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs
index f4b915c06..ebff81b7f 100644
--- a/MediaBrowser.Controller/Providers/MetadataResult.cs
+++ b/MediaBrowser.Controller/Providers/MetadataResult.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Providers
@@ -55,7 +56,7 @@ namespace MediaBrowser.Controller.Providers
foreach (var i in UserDataList)
{
- if (string.Equals(userId, i.UserId.ToString("N"), StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(userId, i.UserId.ToString("N", CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase))
{
userData = i;
}
diff --git a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs
index b40cc157a..bb80e6025 100644
--- a/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs
+++ b/MediaBrowser.Controller/Resolvers/IResolverIgnoreRule.cs
@@ -8,6 +8,12 @@ namespace MediaBrowser.Controller.Resolvers
/// </summary>
public interface IResolverIgnoreRule
{
+ /// <summary>
+ /// Checks whether or not the file should be ignored.
+ /// </summary>
+ /// <param name="fileInfo">The file information.</param>
+ /// <param name="parent">The parent BaseItem.</param>
+ /// <returns>True if the file should be ignored.</returns>
bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent);
}
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 8677b363f..9ddfb9b01 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -425,7 +425,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false);
- if (!string.IsNullOrEmpty(encodingParam))
+ // FFmpeg automatically convert character encoding when it is UTF-16
+ // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event"
+ if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && (encodingParam == "UTF-16BE" || encodingParam == "UTF-16LE"))
+ {
+ encodingParam = "";
+ }
+ else if (!string.IsNullOrEmpty(encodingParam))
{
encodingParam = " -sub_charenc " + encodingParam;
}
diff --git a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs
index 5988112c2..9e85beb43 100644
--- a/MediaBrowser.Model/Cryptography/ICryptoProvider.cs
+++ b/MediaBrowser.Model/Cryptography/ICryptoProvider.cs
@@ -6,9 +6,14 @@ namespace MediaBrowser.Model.Cryptography
{
public interface ICryptoProvider
{
+ string DefaultHashMethod { get; }
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
Guid GetMD5(string str);
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
byte[] ComputeMD5(Stream str);
+ [Obsolete("Use System.Security.Cryptography.MD5 directly")]
byte[] ComputeMD5(byte[] bytes);
+ [Obsolete("Use System.Security.Cryptography.SHA1 directly")]
byte[] ComputeSHA1(byte[] bytes);
IEnumerable<string> GetSupportedHashMethods();
byte[] ComputeHash(string HashMethod, byte[] bytes);
@@ -17,6 +22,5 @@ namespace MediaBrowser.Model.Cryptography
byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt);
byte[] ComputeHash(PasswordHash hash);
byte[] GenerateSalt();
- string DefaultHashMethod { get; }
}
}
diff --git a/MediaBrowser.Model/Cryptography/PasswordHash.cs b/MediaBrowser.Model/Cryptography/PasswordHash.cs
index f15b27d32..df32fdb00 100644
--- a/MediaBrowser.Model/Cryptography/PasswordHash.cs
+++ b/MediaBrowser.Model/Cryptography/PasswordHash.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Text;
namespace MediaBrowser.Model.Cryptography
@@ -16,86 +17,71 @@ namespace MediaBrowser.Model.Cryptography
private Dictionary<string, string> _parameters = new Dictionary<string, string>();
- private string _salt;
+ private byte[] _salt;
- private byte[] _saltBytes;
-
- private string _hash;
-
- private byte[] _hashBytes;
-
- public string Id { get => _id; set => _id = value; }
-
- public Dictionary<string, string> Parameters { get => _parameters; set => _parameters = value; }
-
- public string Salt { get => _salt; set => _salt = value; }
-
- public byte[] SaltBytes { get => _saltBytes; set => _saltBytes = value; }
-
- public string Hash { get => _hash; set => _hash = value; }
-
- public byte[] HashBytes { get => _hashBytes; set => _hashBytes = value; }
+ private byte[] _hash;
public PasswordHash(string storageString)
{
string[] splitted = storageString.Split('$');
- _id = splitted[1];
- if (splitted[2].Contains("="))
+ // The string should at least contain the hash function and the hash itself
+ if (splitted.Length < 3)
+ {
+ throw new ArgumentException("String doesn't contain enough segments", nameof(storageString));
+ }
+
+ // Start at 1, the first index shouldn't contain any data
+ int index = 1;
+
+ // Name of the hash function
+ _id = splitted[index++];
+
+ // Optional parameters
+ if (splitted[index].IndexOf('=') != -1)
{
- foreach (string paramset in (splitted[2].Split(',')))
+ foreach (string paramset in splitted[index++].Split(','))
{
- if (!string.IsNullOrEmpty(paramset))
+ if (string.IsNullOrEmpty(paramset))
{
- string[] fields = paramset.Split('=');
- if (fields.Length == 2)
- {
- _parameters.Add(fields[0], fields[1]);
- }
- else
- {
- throw new Exception($"Malformed parameter in password hash string {paramset}");
- }
+ continue;
}
+
+ string[] fields = paramset.Split('=');
+ if (fields.Length != 2)
+ {
+ throw new InvalidDataException($"Malformed parameter in password hash string {paramset}");
+ }
+
+ _parameters.Add(fields[0], fields[1]);
}
- if (splitted.Length == 5)
- {
- _salt = splitted[3];
- _saltBytes = ConvertFromByteString(_salt);
- _hash = splitted[4];
- _hashBytes = ConvertFromByteString(_hash);
- }
- else
- {
- _salt = string.Empty;
- _hash = splitted[3];
- _hashBytes = ConvertFromByteString(_hash);
- }
+ }
+
+ // Check if the string also contains a salt
+ if (splitted.Length - index == 2)
+ {
+ _salt = ConvertFromByteString(splitted[index++]);
+ _hash = ConvertFromByteString(splitted[index++]);
}
else
{
- if (splitted.Length == 4)
- {
- _salt = splitted[2];
- _saltBytes = ConvertFromByteString(_salt);
- _hash = splitted[3];
- _hashBytes = ConvertFromByteString(_hash);
- }
- else
- {
- _salt = string.Empty;
- _hash = splitted[2];
- _hashBytes = ConvertFromByteString(_hash);
- }
-
+ _salt = Array.Empty<byte>();
+ _hash = ConvertFromByteString(splitted[index++]);
}
-
}
+ public string Id { get => _id; set => _id = value; }
+
+ public Dictionary<string, string> Parameters { get => _parameters; set => _parameters = value; }
+
+ public byte[] Salt { get => _salt; set => _salt = value; }
+
+ public byte[] Hash { get => _hash; set => _hash = value; }
+
public PasswordHash(ICryptoProvider cryptoProvider)
{
_id = cryptoProvider.DefaultHashMethod;
- _saltBytes = cryptoProvider.GenerateSalt();
- _salt = ConvertToByteString(SaltBytes);
+ _salt = cryptoProvider.GenerateSalt();
+ _hash = Array.Empty<Byte>();
}
public static byte[] ConvertFromByteString(string byteString)
@@ -111,43 +97,45 @@ namespace MediaBrowser.Model.Cryptography
}
public static string ConvertToByteString(byte[] bytes)
- {
- return BitConverter.ToString(bytes).Replace("-", "");
- }
+ => BitConverter.ToString(bytes).Replace("-", string.Empty);
- private string SerializeParameters()
+ private void SerializeParameters(StringBuilder stringBuilder)
{
- string returnString = string.Empty;
- foreach (var KVP in _parameters)
+ if (_parameters.Count == 0)
{
- returnString += $",{KVP.Key}={KVP.Value}";
+ return;
}
- if ((!string.IsNullOrEmpty(returnString)) && returnString[0] == ',')
+ stringBuilder.Append('$');
+ foreach (var pair in _parameters)
{
- returnString = returnString.Remove(0, 1);
+ stringBuilder.Append(pair.Key);
+ stringBuilder.Append('=');
+ stringBuilder.Append(pair.Value);
+ stringBuilder.Append(',');
}
- return returnString;
+ // Remove last ','
+ stringBuilder.Length -= 1;
}
public override string ToString()
{
- string outString = "$" + _id;
- string paramstring = SerializeParameters();
- if (!string.IsNullOrEmpty(paramstring))
- {
- outString += $"${paramstring}";
- }
+ var str = new StringBuilder();
+ str.Append('$');
+ str.Append(_id);
+ SerializeParameters(str);
- if (!string.IsNullOrEmpty(_salt))
+ if (_salt.Length == 0)
{
- outString += $"${_salt}";
+ str.Append('$');
+ str.Append(ConvertToByteString(_salt));
}
- outString += $"${_hash}";
- return outString;
+ str.Append('$');
+ str.Append(ConvertToByteString(_hash));
+
+ return str.ToString();
}
}
-
}
diff --git a/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs b/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs
index 4edbb503b..c443a8ad1 100644
--- a/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs
+++ b/MediaBrowser.Model/Dlna/UpnpDeviceInfo.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
-using MediaBrowser.Model.Net;
+using System.Net;
namespace MediaBrowser.Model.Dlna
{
@@ -8,7 +8,7 @@ namespace MediaBrowser.Model.Dlna
{
public Uri Location { get; set; }
public Dictionary<string, string> Headers { get; set; }
- public IpAddressInfo LocalIpAddress { get; set; }
+ public IPAddress LocalIpAddress { get; set; }
public int LocalPort { get; set; }
}
}
diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs
index 992ccb49b..f80de5524 100644
--- a/MediaBrowser.Model/Net/ISocket.cs
+++ b/MediaBrowser.Model/Net/ISocket.cs
@@ -1,4 +1,5 @@
using System;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
@@ -9,7 +10,7 @@ namespace MediaBrowser.Model.Net
/// </summary>
public interface ISocket : IDisposable
{
- IpAddressInfo LocalIPAddress { get; }
+ IPAddress LocalIPAddress { get; }
Task<SocketReceiveResult> ReceiveAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
@@ -21,6 +22,6 @@ namespace MediaBrowser.Model.Net
/// <summary>
/// Sends a UDP message to a particular end point (uni or multicast).
/// </summary>
- Task SendToAsync(byte[] buffer, int offset, int bytes, IpEndPointInfo endPoint, CancellationToken cancellationToken);
+ Task SendToAsync(byte[] buffer, int offset, int bytes, IPEndPoint endPoint, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Model/Net/ISocketFactory.cs b/MediaBrowser.Model/Net/ISocketFactory.cs
index 69fe134bc..e58f4cc14 100644
--- a/MediaBrowser.Model/Net/ISocketFactory.cs
+++ b/MediaBrowser.Model/Net/ISocketFactory.cs
@@ -1,4 +1,5 @@
using System.IO;
+using System.Net;
namespace MediaBrowser.Model.Net
{
@@ -8,7 +9,7 @@ namespace MediaBrowser.Model.Net
public interface ISocketFactory
{
/// <summary>
- /// Createa a new unicast socket using the specified local port number.
+ /// Creates a new unicast socket using the specified local port number.
/// </summary>
/// <param name="localPort">The local port to bind to.</param>
/// <returns>A <see cref="ISocket"/> implementation.</returns>
@@ -16,15 +17,15 @@ namespace MediaBrowser.Model.Net
ISocket CreateUdpBroadcastSocket(int localPort);
- ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
+ ISocket CreateTcpSocket(IPAddress remoteAddress, int remotePort);
/// <summary>
- /// Createa a new unicast socket using the specified local port number.
+ /// Creates a new unicast socket using the specified local port number.
/// </summary>
- ISocket CreateSsdpUdpSocket(IpAddressInfo localIp, int localPort);
+ ISocket CreateSsdpUdpSocket(IPAddress localIp, int localPort);
/// <summary>
- /// Createa a new multicast socket using the specified multicast IP address, multicast time to live and local port.
+ /// Creates a new multicast socket using the specified multicast IP address, multicast time to live and local port.
/// </summary>
/// <param name="ipAddress">The multicast IP address to bind to.</param>
/// <param name="multicastTimeToLive">The multicast time to live value. Actually a maximum number of network hops for UDP packets.</param>
diff --git a/MediaBrowser.Model/Net/IpAddressInfo.cs b/MediaBrowser.Model/Net/IpAddressInfo.cs
deleted file mode 100644
index 87fa55bca..000000000
--- a/MediaBrowser.Model/Net/IpAddressInfo.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System;
-
-namespace MediaBrowser.Model.Net
-{
- public class IpAddressInfo
- {
- public static IpAddressInfo Any = new IpAddressInfo("0.0.0.0", IpAddressFamily.InterNetwork);
- public static IpAddressInfo IPv6Any = new IpAddressInfo("00000000000000000000", IpAddressFamily.InterNetworkV6);
- public static IpAddressInfo Loopback = new IpAddressInfo("127.0.0.1", IpAddressFamily.InterNetwork);
- public static IpAddressInfo IPv6Loopback = new IpAddressInfo("::1", IpAddressFamily.InterNetworkV6);
-
- public string Address { get; set; }
- public IpAddressInfo SubnetMask { get; set; }
- public IpAddressFamily AddressFamily { get; set; }
-
- public IpAddressInfo(string address, IpAddressFamily addressFamily)
- {
- Address = address;
- AddressFamily = addressFamily;
- }
-
- public bool Equals(IpAddressInfo address)
- {
- return string.Equals(address.Address, Address, StringComparison.OrdinalIgnoreCase);
- }
-
- public override string ToString()
- {
- return Address;
- }
- }
-
- public enum IpAddressFamily
- {
- InterNetwork,
- InterNetworkV6
- }
-}
diff --git a/MediaBrowser.Model/Net/IpEndPointInfo.cs b/MediaBrowser.Model/Net/IpEndPointInfo.cs
deleted file mode 100644
index f8c125144..000000000
--- a/MediaBrowser.Model/Net/IpEndPointInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Globalization;
-
-namespace MediaBrowser.Model.Net
-{
- public class IpEndPointInfo
- {
- public IpAddressInfo IpAddress { get; set; }
-
- public int Port { get; set; }
-
- public IpEndPointInfo()
- {
-
- }
-
- public IpEndPointInfo(IpAddressInfo address, int port)
- {
- IpAddress = address;
- Port = port;
- }
-
- public override string ToString()
- {
- var ipAddresString = IpAddress == null ? string.Empty : IpAddress.ToString();
-
- return ipAddresString + ":" + Port.ToString(CultureInfo.InvariantCulture);
- }
- }
-}
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 659abe84c..d7bf956bb 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -12,113 +12,133 @@ namespace MediaBrowser.Model.Net
public static class MimeTypes
{
/// <summary>
- /// Any extension in this list is considered a video file - can be added to at runtime for extensibility
+ /// Any extension in this list is considered a video file
/// </summary>
- private static readonly string[] VideoFileExtensions = new string[]
- {
- ".mkv",
- ".m2t",
- ".m2ts",
- ".img",
- ".iso",
- ".mk3d",
- ".ts",
- ".rmvb",
- ".mov",
- ".avi",
- ".mpg",
- ".mpeg",
- ".wmv",
- ".mp4",
- ".divx",
- ".dvr-ms",
- ".wtv",
- ".ogm",
- ".ogv",
- ".asf",
- ".m4v",
- ".flv",
- ".f4v",
- ".3gp",
- ".webm",
- ".mts",
- ".m2v",
- ".rec"
- };
-
- private static Dictionary<string, string> GetVideoFileExtensionsDictionary()
+ private static readonly HashSet<string> _videoFileExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
- var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-
- foreach (string ext in VideoFileExtensions)
- {
- dict[ext] = ext;
- }
-
- return dict;
- }
-
- private static readonly Dictionary<string, string> VideoFileExtensionsDictionary = GetVideoFileExtensionsDictionary();
+ ".mkv",
+ ".m2t",
+ ".m2ts",
+ ".img",
+ ".iso",
+ ".mk3d",
+ ".ts",
+ ".rmvb",
+ ".mov",
+ ".avi",
+ ".mpg",
+ ".mpeg",
+ ".wmv",
+ ".mp4",
+ ".divx",
+ ".dvr-ms",
+ ".wtv",
+ ".ogm",
+ ".ogv",
+ ".asf",
+ ".m4v",
+ ".flv",
+ ".f4v",
+ ".3gp",
+ ".webm",
+ ".mts",
+ ".m2v",
+ ".rec"
+ };
// http://en.wikipedia.org/wiki/Internet_media_type
// Add more as needed
-
- private static Dictionary<string, string> GetMimeTypeLookup()
+ private static readonly Dictionary<string, string> _mimeTypeLookup = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
- var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ // Type application
+ { ".cbz", "application/x-cbz" },
+ { ".cbr", "application/epub+zip" },
+ { ".eot", "application/vnd.ms-fontobject" },
+ { ".epub", "application/epub+zip" },
+ { ".js", "application/x-javascript" },
+ { ".json", "application/json" },
+ { ".map", "application/x-javascript" },
+ { ".pdf", "application/pdf" },
+ { ".ttml", "application/ttml+xml" },
+ { ".m3u8", "application/x-mpegURL" },
+ { ".mobi", "application/x-mobipocket-ebook" },
+ { ".xml", "application/xml" },
+
+ // Type image
+ { ".jpg", "image/jpeg" },
+ { ".jpeg", "image/jpeg" },
+ { ".tbn", "image/jpeg" },
+ { ".png", "image/png" },
+ { ".gif", "image/gif" },
+ { ".tiff", "image/tiff" },
+ { ".webp", "image/webp" },
+ { ".ico", "image/vnd.microsoft.icon" },
+ { ".svg", "image/svg+xml" },
+ { ".svgz", "image/svg+xml" },
+
+ // Type font
+ { ".ttf" , "font/ttf" },
+ { ".woff" , "font/woff" },
- dict.Add(".jpg", "image/jpeg");
- dict.Add(".jpeg", "image/jpeg");
- dict.Add(".tbn", "image/jpeg");
- dict.Add(".png", "image/png");
- dict.Add(".gif", "image/gif");
- dict.Add(".tiff", "image/tiff");
- dict.Add(".webp", "image/webp");
- dict.Add(".ico", "image/vnd.microsoft.icon");
- dict.Add(".mpg", "video/mpeg");
- dict.Add(".mpeg", "video/mpeg");
- dict.Add(".ogv", "video/ogg");
- dict.Add(".mov", "video/quicktime");
- dict.Add(".webm", "video/webm");
- dict.Add(".mkv", "video/x-matroska");
- dict.Add(".wmv", "video/x-ms-wmv");
- dict.Add(".flv", "video/x-flv");
- dict.Add(".avi", "video/x-msvideo");
- dict.Add(".asf", "video/x-ms-asf");
- dict.Add(".m4v", "video/x-m4v");
- dict.Add(".m4s", "video/mp4");
- dict.Add(".cbz", "application/x-cbz");
- dict.Add(".cbr", "application/epub+zip");
- dict.Add(".epub", "application/epub+zip");
- dict.Add(".pdf", "application/pdf");
- dict.Add(".mobi", "application/x-mobipocket-ebook");
-
- dict.Add(".ass", "text/x-ssa");
- dict.Add(".ssa", "text/x-ssa");
+ // Type text
+ { ".ass", "text/x-ssa" },
+ { ".ssa", "text/x-ssa" },
+ { ".css", "text/css" },
+ { ".csv", "text/csv" },
+ { ".txt", "text/plain" },
+ { ".vtt", "text/vtt" },
- return dict;
- }
+ // Type video
+ { ".mpg", "video/mpeg" },
+ { ".ogv", "video/ogg" },
+ { ".mov", "video/quicktime" },
+ { ".webm", "video/webm" },
+ { ".mkv", "video/x-matroska" },
+ { ".wmv", "video/x-ms-wmv" },
+ { ".flv", "video/x-flv" },
+ { ".avi", "video/x-msvideo" },
+ { ".asf", "video/x-ms-asf" },
+ { ".m4v", "video/x-m4v" },
+ { ".m4s", "video/mp4" },
+ { ".3gp", "video/3gpp" },
+ { ".3g2", "video/3gpp2" },
+ { ".mpd", "video/vnd.mpeg.dash.mpd" },
+ { ".ts", "video/mp2t" },
- private static readonly Dictionary<string, string> MimeTypeLookup = GetMimeTypeLookup();
+ // Type audio
+ { ".mp3", "audio/mpeg" },
+ { ".m4a", "audio/mp4" },
+ { ".aac", "audio/mp4" },
+ { ".webma", "audio/webm" },
+ { ".wav", "audio/wav" },
+ { ".wma", "audio/x-ms-wma" },
+ { ".ogg", "audio/ogg" },
+ { ".oga", "audio/ogg" },
+ { ".opus", "audio/ogg" },
+ { ".ac3", "audio/ac3" },
+ { ".dsf", "audio/dsf" },
+ { ".m4b", "audio/m4b" },
+ { ".xsp", "audio/xsp" },
+ { ".dsp", "audio/dsp" },
+ };
- private static readonly Dictionary<string, string> ExtensionLookup = CreateExtensionLookup();
+ private static readonly Dictionary<string, string> _extensionLookup = CreateExtensionLookup();
private static Dictionary<string, string> CreateExtensionLookup()
{
- var dict = MimeTypeLookup
+ var dict = _mimeTypeLookup
.GroupBy(i => i.Value)
.ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase);
dict["image/jpg"] = ".jpg";
dict["image/x-png"] = ".png";
+ dict["audio/x-aac"] = ".aac";
+
return dict;
}
- public static string GetMimeType(string path)
- {
- return GetMimeType(path, true);
- }
+ public static string GetMimeType(string path) => GetMimeType(path, true);
/// <summary>
/// Gets the type of the MIME.
@@ -130,137 +150,30 @@ namespace MediaBrowser.Model.Net
throw new ArgumentNullException(nameof(path));
}
- var ext = Path.GetExtension(path) ?? string.Empty;
+ var ext = Path.GetExtension(path);
- if (MimeTypeLookup.TryGetValue(ext, out string result))
+ if (_mimeTypeLookup.TryGetValue(ext, out string result))
{
return result;
}
- // Type video
- if (StringHelper.EqualsIgnoreCase(ext, ".3gp"))
- {
- return "video/3gpp";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".3g2"))
- {
- return "video/3gpp2";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".ts"))
- {
- return "video/mp2t";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".mpd"))
- {
- return "video/vnd.mpeg.dash.mpd";
- }
-
// Catch-all for all video types that don't require specific mime types
- if (VideoFileExtensionsDictionary.ContainsKey(ext))
+ if (_videoFileExtensions.Contains(ext))
{
- return "video/" + ext.TrimStart('.').ToLowerInvariant();
+ return "video/" + ext.Substring(1);
}
// Type text
- if (StringHelper.EqualsIgnoreCase(ext, ".css"))
- {
- return "text/css";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".csv"))
- {
- return "text/csv";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".html"))
+ if (StringHelper.EqualsIgnoreCase(ext, ".html")
+ || StringHelper.EqualsIgnoreCase(ext, ".htm"))
{
return "text/html; charset=UTF-8";
}
- if (StringHelper.EqualsIgnoreCase(ext, ".htm"))
- {
- return "text/html; charset=UTF-8";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".txt"))
- {
- return "text/plain";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".log"))
- {
- return "text/plain";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".xml"))
- {
- return "application/xml";
- }
- // Type audio
- if (StringHelper.EqualsIgnoreCase(ext, ".mp3"))
- {
- return "audio/mpeg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".m4a"))
- {
- return "audio/mp4";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".aac"))
+ if (StringHelper.EqualsIgnoreCase(ext, ".log")
+ || StringHelper.EqualsIgnoreCase(ext, ".srt"))
{
- return "audio/mp4";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".webma"))
- {
- return "audio/webm";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".wav"))
- {
- return "audio/wav";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".wma"))
- {
- return "audio/x-ms-wma";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".flac"))
- {
- return "audio/flac";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".aac"))
- {
- return "audio/x-aac";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".ogg"))
- {
- return "audio/ogg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".oga"))
- {
- return "audio/ogg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".opus"))
- {
- return "audio/ogg";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".ac3"))
- {
- return "audio/ac3";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".dsf"))
- {
- return "audio/dsf";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".m4b"))
- {
- return "audio/m4b";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".xsp"))
- {
- return "audio/xsp";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".dsp"))
- {
- return "audio/dsp";
- }
-
- // Playlists
- if (StringHelper.EqualsIgnoreCase(ext, ".m3u8"))
- {
- return "application/x-mpegURL";
+ return "text/plain";
}
// Misc
@@ -269,63 +182,7 @@ namespace MediaBrowser.Model.Net
return "application/octet-stream";
}
- // Web
- if (StringHelper.EqualsIgnoreCase(ext, ".js"))
- {
- return "application/x-javascript";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".json"))
- {
- return "application/json";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".map"))
- {
- return "application/x-javascript";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".woff"))
- {
- return "font/woff";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".ttf"))
- {
- return "font/ttf";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".eot"))
- {
- return "application/vnd.ms-fontobject";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".svg"))
- {
- return "image/svg+xml";
- }
- if (StringHelper.EqualsIgnoreCase(ext, ".svgz"))
- {
- return "image/svg+xml";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".srt"))
- {
- return "text/plain";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".vtt"))
- {
- return "text/vtt";
- }
-
- if (StringHelper.EqualsIgnoreCase(ext, ".ttml"))
- {
- return "application/ttml+xml";
- }
-
- if (enableStreamDefault)
- {
- return "application/octet-stream";
- }
-
- return null;
+ return enableStreamDefault ? "application/octet-stream" : null;
}
public static string ToExtension(string mimeType)
@@ -338,10 +195,11 @@ namespace MediaBrowser.Model.Net
// handle text/html; charset=UTF-8
mimeType = mimeType.Split(';')[0];
- if (ExtensionLookup.TryGetValue(mimeType, out string result))
+ if (_extensionLookup.TryGetValue(mimeType, out string result))
{
return result;
}
+
return null;
}
}
diff --git a/MediaBrowser.Model/Net/SocketReceiveResult.cs b/MediaBrowser.Model/Net/SocketReceiveResult.cs
index 8c394f7c7..cd7a2e55f 100644
--- a/MediaBrowser.Model/Net/SocketReceiveResult.cs
+++ b/MediaBrowser.Model/Net/SocketReceiveResult.cs
@@ -1,3 +1,5 @@
+using System.Net;
+
namespace MediaBrowser.Model.Net
{
/// <summary>
@@ -18,7 +20,7 @@ namespace MediaBrowser.Model.Net
/// <summary>
/// The <see cref="IpEndPointInfo"/> the data was received from.
/// </summary>
- public IpEndPointInfo RemoteEndPoint { get; set; }
- public IpAddressInfo LocalIPAddress { get; set; }
+ public IPEndPoint RemoteEndPoint { get; set; }
+ public IPAddress LocalIPAddress { get; set; }
}
}
diff --git a/MediaBrowser.Model/Services/IHasRequestFilter.cs b/MediaBrowser.Model/Services/IHasRequestFilter.cs
index d4e6aa8e0..81a2dba69 100644
--- a/MediaBrowser.Model/Services/IHasRequestFilter.cs
+++ b/MediaBrowser.Model/Services/IHasRequestFilter.cs
@@ -1,3 +1,5 @@
+using Microsoft.AspNetCore.Http;
+
namespace MediaBrowser.Model.Services
{
public interface IHasRequestFilter
@@ -15,6 +17,6 @@ namespace MediaBrowser.Model.Services
/// <param name="req">The http request wrapper</param>
/// <param name="res">The http response wrapper</param>
/// <param name="requestDto">The request DTO</param>
- void RequestFilter(IRequest req, IResponse res, object requestDto);
+ void RequestFilter(IRequest req, HttpResponse res, object requestDto);
}
}
diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs
index 4f6ddb476..7a4152698 100644
--- a/MediaBrowser.Model/Services/IRequest.cs
+++ b/MediaBrowser.Model/Services/IRequest.cs
@@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Model.Services
{
public interface IRequest
{
- IResponse Response { get; }
+ HttpResponse Response { get; }
/// <summary>
/// The name of the service being called (e.g. Request DTO Name)
@@ -23,11 +20,6 @@ namespace MediaBrowser.Model.Services
string Verb { get; }
/// <summary>
- /// The Request DTO, after it has been deserialized.
- /// </summary>
- object Dto { get; set; }
-
- /// <summary>
/// The request ContentType
/// </summary>
string ContentType { get; }
@@ -50,8 +42,6 @@ namespace MediaBrowser.Model.Services
IQueryCollection QueryString { get; }
- Task<QueryParamCollection> GetFormData();
-
string RawUrl { get; }
string AbsoluteUri { get; }
@@ -75,11 +65,6 @@ namespace MediaBrowser.Model.Services
long ContentLength { get; }
/// <summary>
- /// Access to the multi-part/formdata files posted on this request
- /// </summary>
- IHttpFile[] Files { get; }
-
- /// <summary>
/// The value of the Referrer, null if not available
/// </summary>
Uri UrlReferrer { get; }
@@ -98,25 +83,4 @@ namespace MediaBrowser.Model.Services
{
IRequest Request { get; set; }
}
-
- public interface IResponse
- {
- HttpResponse OriginalResponse { get; }
-
- int StatusCode { get; set; }
-
- string StatusDescription { get; set; }
-
- string ContentType { get; set; }
-
- void AddHeader(string name, string value);
-
- void Redirect(string url);
-
- Stream OutputStream { get; }
-
- Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, IFileSystem fileSystem, IStreamHelper streamHelper, CancellationToken cancellationToken);
-
- bool SendChunked { get; set; }
- }
}
diff --git a/MediaBrowser.Model/System/WakeOnLanInfo.cs b/MediaBrowser.Model/System/WakeOnLanInfo.cs
index 031458735..534ad19ec 100644
--- a/MediaBrowser.Model/System/WakeOnLanInfo.cs
+++ b/MediaBrowser.Model/System/WakeOnLanInfo.cs
@@ -1,10 +1,47 @@
+using System.Net.NetworkInformation;
+
namespace MediaBrowser.Model.System
{
+ /// <summary>
+ /// Provides the MAC address and port for wake-on-LAN functionality.
+ /// </summary>
public class WakeOnLanInfo
{
+ /// <summary>
+ /// Returns the MAC address of the device.
+ /// </summary>
+ /// <value>The MAC address.</value>
public string MacAddress { get; set; }
+
+ /// <summary>
+ /// Returns the wake-on-LAN port.
+ /// </summary>
+ /// <value>The wake-on-LAN port.</value>
public int Port { get; set; }
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WakeOnLanInfo" /> class.
+ /// </summary>
+ /// <param name="macAddress">The MAC address.</param>
+ public WakeOnLanInfo(PhysicalAddress macAddress)
+ {
+ MacAddress = macAddress.ToString();
+ Port = 9;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WakeOnLanInfo" /> class.
+ /// </summary>
+ /// <param name="macAddress">The MAC address.</param>
+ public WakeOnLanInfo(string macAddress)
+ {
+ MacAddress = macAddress;
+ Port = 9;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WakeOnLanInfo" /> class.
+ /// </summary>
public WakeOnLanInfo()
{
Port = 9;
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 860ea13cf..a22eaaa51 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -934,7 +934,7 @@ namespace MediaBrowser.Providers.Manager
public void OnRefreshStart(BaseItem item)
{
- //_logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N"));
+ //_logger.LogInformation("OnRefreshStart {0}", item.Id.ToString("N", CultureInfo.InvariantCulture));
var id = item.Id;
lock (_activeRefreshes)
@@ -947,7 +947,7 @@ namespace MediaBrowser.Providers.Manager
public void OnRefreshComplete(BaseItem item)
{
- //_logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N"));
+ //_logger.LogInformation("OnRefreshComplete {0}", item.Id.ToString("N", CultureInfo.InvariantCulture));
lock (_activeRefreshes)
{
_activeRefreshes.Remove(item.Id);
@@ -971,7 +971,7 @@ namespace MediaBrowser.Providers.Manager
public void OnRefreshProgress(BaseItem item, double progress)
{
- //_logger.LogInformation("OnRefreshProgress {0} {1}", item.Id.ToString("N"), progress);
+ //_logger.LogInformation("OnRefreshProgress {0} {1}", item.Id.ToString("N", CultureInfo.InvariantCulture), progress);
var id = item.Id;
lock (_activeRefreshes)
@@ -985,7 +985,7 @@ namespace MediaBrowser.Providers.Manager
else
{
// TODO: Need to hunt down the conditions for this happening
- //throw new Exception(string.Format("Refresh for item {0} {1} is not in progress", item.GetType().Name, item.Id.ToString("N")));
+ //throw new Exception(string.Format("Refresh for item {0} {1} is not in progress", item.GetType().Name, item.Id.ToString("N", CultureInfo.InvariantCulture)));
}
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 61a8a122b..7023ef706 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
@@ -99,11 +100,11 @@ namespace MediaBrowser.Providers.MediaInfo
if (!string.IsNullOrWhiteSpace(item.Album) && !string.IsNullOrWhiteSpace(albumArtist))
{
- filename = (item.Album + "-" + albumArtist).GetMD5().ToString("N");
+ filename = (item.Album + "-" + albumArtist).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
else
{
- filename = item.Id.ToString("N");
+ filename = item.Id.ToString("N", CultureInfo.InvariantCulture);
}
filename += ".jpg";
@@ -111,7 +112,7 @@ namespace MediaBrowser.Providers.MediaInfo
else
{
// If it's an audio book or audio podcast, allow unique image per item
- filename = item.Id.ToString("N") + ".jpg";
+ filename = item.Id.ToString("N", CultureInfo.InvariantCulture) + ".jpg";
}
var prefix = filename.Substring(0, 1);
diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
index 7fc6909f5..b4a4c36e5 100644
--- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
+++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs
@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -296,7 +295,7 @@ namespace MediaBrowser.Providers.Subtitles
private string GetProviderId(string name)
{
- return name.ToLowerInvariant().GetMD5().ToString("N");
+ return name.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
private ISubtitleProvider GetProvider(string id)
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
index 85833223e..5cd0a6ab8 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvDbClientManager.cs
@@ -162,8 +162,21 @@ namespace MediaBrowser.Providers.TV.TheTVDB
// Prefer SxE over premiere date as it is more robust
if (searchInfo.IndexNumber.HasValue && searchInfo.ParentIndexNumber.HasValue)
{
- episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value;
- episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value;
+ switch (searchInfo.SeriesDisplayOrder)
+ {
+ case "dvd":
+ episodeQuery.DvdEpisode = searchInfo.IndexNumber.Value;
+ episodeQuery.DvdSeason = searchInfo.ParentIndexNumber.Value;
+ break;
+ case "absolute":
+ episodeQuery.AbsoluteNumber = searchInfo.IndexNumber.Value;
+ break;
+ default:
+ //aired order
+ episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value;
+ episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value;
+ break;
+ }
}
else if (searchInfo.PremiereDate.HasValue)
{
diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
index 5ea73dfbf..c739f3f49 100644
--- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
@@ -355,7 +355,10 @@ namespace MediaBrowser.Providers.TV.TheTVDB
series.AddGenre(genre);
}
- series.AddStudio(tvdbSeries.Network);
+ if (!string.IsNullOrEmpty(tvdbSeries.Network))
+ {
+ series.AddStudio(tvdbSeries.Network);
+ }
if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended)
{
diff --git a/README.md b/README.md
index 643c59a73..800a72da1 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
<a href="https://hub.docker.com/r/jellyfin/jellyfin"><img alt="Docker Pull Count" src="https://img.shields.io/docker/pulls/jellyfin/jellyfin.svg"/></a>
</br>
<a href="https://opencollective.com/jellyfin"><img alt="Donate" src="https://img.shields.io/opencollective/all/jellyfin.svg?label=backers"/></a>
+<a href="https://features.jellyfin.org"/><img alt="Submit and vote on feature requests" src="https://img.shields.io/badge/fider-vote%20on%20features-success.svg"/></a>
<a href="https://forum.jellyfin.org"/><img alt="Discuss on our Forum" src="https://img.shields.io/discourse/https/forum.jellyfin.org/users.svg"/></a>
<a href="https://matrix.to/#/+jellyfin:matrix.org"><img alt="Chat on Matrix" src="https://img.shields.io/matrix/jellyfin:matrix.org.svg?logo=matrix"/></a>
<a href="https://www.reddit.com/r/jellyfin/"><img alt="Join our Subreddit" src="https://img.shields.io/badge/reddit-r%2Fjellyfin-%23FF5700.svg"/></a>
@@ -35,6 +36,10 @@ For more information about the project, please see our [about page](https://jell
<em>Check out <a href="https://jellyfin.readthedocs.io/en/latest/contributor-docs/contributing/">our documentation for guidelines</a>.</em>
</p>
<p align="center">
-<strong>New idea or improvement? Something not working right?</strong>
+<strong>New idea or improvement?</strong>
+<em>Check out our <a href="https://features.jellyfin.org/?view=most-wanted">feature request hub</a>.</em>
+</p>
+<p align="center">
+<strong>Something not working right?</strong>
<em>Open an <a href="https://jellyfin.readthedocs.io/en/latest/contributor-docs/issues/">Issue</a>.</em>
</p>
diff --git a/RSSDP/DeviceAvailableEventArgs.cs b/RSSDP/DeviceAvailableEventArgs.cs
index 9106e27e5..21ac7c631 100644
--- a/RSSDP/DeviceAvailableEventArgs.cs
+++ b/RSSDP/DeviceAvailableEventArgs.cs
@@ -1,8 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
+using System.Net;
namespace Rssdp
{
@@ -11,12 +8,12 @@ namespace Rssdp
/// </summary>
public sealed class DeviceAvailableEventArgs : EventArgs
{
- public IpAddressInfo LocalIpAddress { get; set; }
+ public IPAddress LocalIpAddress { get; set; }
#region Fields
private readonly DiscoveredSsdpDevice _DiscoveredDevice;
- private readonly bool _IsNewlyDiscovered;
+ private readonly bool _IsNewlyDiscovered;
#endregion
@@ -29,34 +26,34 @@ namespace Rssdp
/// <param name="isNewlyDiscovered">A boolean value indicating whether or not this device came from the cache. See <see cref="IsNewlyDiscovered"/> for more detail.</param>
/// <exception cref="ArgumentNullException">Thrown if the <paramref name="discoveredDevice"/> parameter is null.</exception>
public DeviceAvailableEventArgs(DiscoveredSsdpDevice discoveredDevice, bool isNewlyDiscovered)
- {
- if (discoveredDevice == null) throw new ArgumentNullException(nameof(discoveredDevice));
+ {
+ if (discoveredDevice == null) throw new ArgumentNullException(nameof(discoveredDevice));
- _DiscoveredDevice = discoveredDevice;
- _IsNewlyDiscovered = isNewlyDiscovered;
- }
+ _DiscoveredDevice = discoveredDevice;
+ _IsNewlyDiscovered = isNewlyDiscovered;
+ }
- #endregion
+ #endregion
- #region Public Properties
+ #region Public Properties
- /// <summary>
- /// Returns true if the device was discovered due to an alive notification, or a search and was not already in the cache. Returns false if the item came from the cache but matched the current search request.
- /// </summary>
- public bool IsNewlyDiscovered
- {
- get { return _IsNewlyDiscovered; }
- }
+ /// <summary>
+ /// Returns true if the device was discovered due to an alive notification, or a search and was not already in the cache. Returns false if the item came from the cache but matched the current search request.
+ /// </summary>
+ public bool IsNewlyDiscovered
+ {
+ get { return _IsNewlyDiscovered; }
+ }
/// <summary>
/// A reference to a <see cref="DiscoveredSsdpDevice"/> instance containing the discovered details and allowing access to the full device description.
/// </summary>
public DiscoveredSsdpDevice DiscoveredDevice
- {
- get { return _DiscoveredDevice; }
- }
-
- #endregion
-
- }
-} \ No newline at end of file
+ {
+ get { return _DiscoveredDevice; }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/RSSDP/ISsdpCommunicationsServer.cs b/RSSDP/ISsdpCommunicationsServer.cs
index c99d684a1..8cf65df11 100644
--- a/RSSDP/ISsdpCommunicationsServer.cs
+++ b/RSSDP/ISsdpCommunicationsServer.cs
@@ -1,7 +1,7 @@
using System;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -40,13 +40,13 @@ namespace Rssdp.Infrastructure
/// <summary>
/// Sends a message to a particular address (uni or multicast) and port.
/// </summary>
- Task SendMessage(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
+ Task SendMessage(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken);
/// <summary>
/// Sends a message to the SSDP multicast address and port.
/// </summary>
- Task SendMulticastMessage(string message, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
- Task SendMulticastMessage(string message, int sendCount, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
+ Task SendMulticastMessage(string message, IPAddress fromLocalIpAddress, CancellationToken cancellationToken);
+ Task SendMulticastMessage(string message, int sendCount, IPAddress fromLocalIpAddress, CancellationToken cancellationToken);
#endregion
diff --git a/RSSDP/RequestReceivedEventArgs.cs b/RSSDP/RequestReceivedEventArgs.cs
index fd3cd9e3a..b753950f0 100644
--- a/RSSDP/RequestReceivedEventArgs.cs
+++ b/RSSDP/RequestReceivedEventArgs.cs
@@ -1,10 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Net;
using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -16,18 +12,18 @@ namespace Rssdp.Infrastructure
#region Fields
private readonly HttpRequestMessage _Message;
- private readonly IpEndPointInfo _ReceivedFrom;
+ private readonly IPEndPoint _ReceivedFrom;
#endregion
- public IpAddressInfo LocalIpAddress { get; private set; }
+ public IPAddress LocalIpAddress { get; private set; }
#region Constructors
/// <summary>
/// Full constructor.
/// </summary>
- public RequestReceivedEventArgs(HttpRequestMessage message, IpEndPointInfo receivedFrom, IpAddressInfo localIpAddress)
+ public RequestReceivedEventArgs(HttpRequestMessage message, IPEndPoint receivedFrom, IPAddress localIpAddress)
{
_Message = message;
_ReceivedFrom = receivedFrom;
@@ -49,7 +45,7 @@ namespace Rssdp.Infrastructure
/// <summary>
/// The <see cref="UdpEndPoint"/> the request came from.
/// </summary>
- public IpEndPointInfo ReceivedFrom
+ public IPEndPoint ReceivedFrom
{
get { return _ReceivedFrom; }
}
diff --git a/RSSDP/ResponseReceivedEventArgs.cs b/RSSDP/ResponseReceivedEventArgs.cs
index 5ed9664ed..f9f9c3040 100644
--- a/RSSDP/ResponseReceivedEventArgs.cs
+++ b/RSSDP/ResponseReceivedEventArgs.cs
@@ -1,10 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Net;
using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -14,12 +10,12 @@ namespace Rssdp.Infrastructure
public sealed class ResponseReceivedEventArgs : EventArgs
{
- public IpAddressInfo LocalIpAddress { get; set; }
+ public IPAddress LocalIpAddress { get; set; }
#region Fields
private readonly HttpResponseMessage _Message;
- private readonly IpEndPointInfo _ReceivedFrom;
+ private readonly IPEndPoint _ReceivedFrom;
#endregion
@@ -28,7 +24,7 @@ namespace Rssdp.Infrastructure
/// <summary>
/// Full constructor.
/// </summary>
- public ResponseReceivedEventArgs(HttpResponseMessage message, IpEndPointInfo receivedFrom)
+ public ResponseReceivedEventArgs(HttpResponseMessage message, IPEndPoint receivedFrom)
{
_Message = message;
_ReceivedFrom = receivedFrom;
@@ -49,7 +45,7 @@ namespace Rssdp.Infrastructure
/// <summary>
/// The <see cref="UdpEndPoint"/> the response came from.
/// </summary>
- public IpEndPointInfo ReceivedFrom
+ public IPEndPoint ReceivedFrom
{
get { return _ReceivedFrom; }
}
diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs
index 5d2afc37a..0aa985a26 100644
--- a/RSSDP/SsdpCommunicationsServer.cs
+++ b/RSSDP/SsdpCommunicationsServer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
@@ -163,7 +164,7 @@ namespace Rssdp.Infrastructure
/// <summary>
/// Sends a message to a particular address (uni or multicast) and port.
/// </summary>
- public async Task SendMessage(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ public async Task SendMessage(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
if (messageData == null) throw new ArgumentNullException(nameof(messageData));
@@ -186,7 +187,7 @@ namespace Rssdp.Infrastructure
}
}
- private async Task SendFromSocket(ISocket socket, byte[] messageData, IpEndPointInfo destination, CancellationToken cancellationToken)
+ private async Task SendFromSocket(ISocket socket, byte[] messageData, IPEndPoint destination, CancellationToken cancellationToken)
{
try
{
@@ -206,7 +207,7 @@ namespace Rssdp.Infrastructure
}
}
- private List<ISocket> GetSendSockets(IpAddressInfo fromLocalIpAddress, IpEndPointInfo destination)
+ private List<ISocket> GetSendSockets(IPAddress fromLocalIpAddress, IPEndPoint destination)
{
EnsureSendSocketCreated();
@@ -215,24 +216,24 @@ namespace Rssdp.Infrastructure
var sockets = _sendSockets.Where(i => i.LocalIPAddress.AddressFamily == fromLocalIpAddress.AddressFamily);
// Send from the Any socket and the socket with the matching address
- if (fromLocalIpAddress.AddressFamily == IpAddressFamily.InterNetwork)
+ if (fromLocalIpAddress.AddressFamily == AddressFamily.InterNetwork)
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
// If sending to the loopback address, filter the socket list as well
- if (destination.IpAddress.Equals(IpAddressInfo.Loopback))
+ if (destination.Address.Equals(IPAddress.Loopback))
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.Any) || i.LocalIPAddress.Equals(IpAddressInfo.Loopback));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.Any) || i.LocalIPAddress.Equals(IPAddress.Loopback));
}
}
- else if (fromLocalIpAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
+ else if (fromLocalIpAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.IPv6Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.IPv6Any) || fromLocalIpAddress.Equals(i.LocalIPAddress));
// If sending to the loopback address, filter the socket list as well
- if (destination.IpAddress.Equals(IpAddressInfo.IPv6Loopback))
+ if (destination.Address.Equals(IPAddress.IPv6Loopback))
{
- sockets = sockets.Where(i => i.LocalIPAddress.Equals(IpAddressInfo.IPv6Any) || i.LocalIPAddress.Equals(IpAddressInfo.IPv6Loopback));
+ sockets = sockets.Where(i => i.LocalIPAddress.Equals(IPAddress.IPv6Any) || i.LocalIPAddress.Equals(IPAddress.IPv6Loopback));
}
}
@@ -240,7 +241,7 @@ namespace Rssdp.Infrastructure
}
}
- public Task SendMulticastMessage(string message, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ public Task SendMulticastMessage(string message, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
return SendMulticastMessage(message, SsdpConstants.UdpResendCount, fromLocalIpAddress, cancellationToken);
}
@@ -248,7 +249,7 @@ namespace Rssdp.Infrastructure
/// <summary>
/// Sends a message to the SSDP multicast address and port.
/// </summary>
- public async Task SendMulticastMessage(string message, int sendCount, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ public async Task SendMulticastMessage(string message, int sendCount, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
if (message == null) throw new ArgumentNullException(nameof(message));
@@ -263,12 +264,13 @@ namespace Rssdp.Infrastructure
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
for (var i = 0; i < sendCount; i++)
{
- await SendMessageIfSocketNotDisposed(messageData, new IpEndPointInfo
- {
- IpAddress = new IpAddressInfo(SsdpConstants.MulticastLocalAdminAddress, IpAddressFamily.InterNetwork),
- Port = SsdpConstants.MulticastPort
-
- }, fromLocalIpAddress, cancellationToken).ConfigureAwait(false);
+ await SendMessageIfSocketNotDisposed(
+ messageData,
+ new IPEndPoint(
+ IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress),
+ SsdpConstants.MulticastPort),
+ fromLocalIpAddress,
+ cancellationToken).ConfigureAwait(false);
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
}
@@ -336,7 +338,7 @@ namespace Rssdp.Infrastructure
#region Private Methods
- private Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
+ private Task SendMessageIfSocketNotDisposed(byte[] messageData, IPEndPoint destination, IPAddress fromLocalIpAddress, CancellationToken cancellationToken)
{
var sockets = _sendSockets;
if (sockets != null)
@@ -364,13 +366,13 @@ namespace Rssdp.Infrastructure
{
var sockets = new List<ISocket>();
- sockets.Add(_SocketFactory.CreateSsdpUdpSocket(IpAddressInfo.Any, _LocalPort));
+ sockets.Add(_SocketFactory.CreateSsdpUdpSocket(IPAddress.Any, _LocalPort));
if (_enableMultiSocketBinding)
{
foreach (var address in _networkManager.GetLocalIpAddresses(_config.Configuration.IgnoreVirtualInterfaces))
{
- if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
+ if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
// Not support IPv6 right now
continue;
@@ -439,7 +441,7 @@ namespace Rssdp.Infrastructure
}
}
- private void ProcessMessage(string data, IpEndPointInfo endPoint, IpAddressInfo receivedOnLocalIpAddress)
+ private void ProcessMessage(string data, IPEndPoint endPoint, IPAddress receivedOnLocalIpAddress)
{
// Responses start with the HTTP version, prefixed with HTTP/ while
// requests start with a method which can vary and might be one we haven't
@@ -481,7 +483,7 @@ namespace Rssdp.Infrastructure
}
}
- private void OnRequestReceived(HttpRequestMessage data, IpEndPointInfo remoteEndPoint, IpAddressInfo receivedOnLocalIpAddress)
+ private void OnRequestReceived(HttpRequestMessage data, IPEndPoint remoteEndPoint, IPAddress receivedOnLocalIpAddress)
{
//SSDP specification says only * is currently used but other uri's might
//be implemented in the future and should be ignored unless understood.
@@ -496,7 +498,7 @@ namespace Rssdp.Infrastructure
handlers(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnLocalIpAddress));
}
- private void OnResponseReceived(HttpResponseMessage data, IpEndPointInfo endPoint, IpAddressInfo localIpAddress)
+ private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIpAddress)
{
var handlers = this.ResponseReceived;
if (handlers != null)
diff --git a/RSSDP/SsdpDevice.cs b/RSSDP/SsdpDevice.cs
index b4c4a88fd..09f729e83 100644
--- a/RSSDP/SsdpDevice.cs
+++ b/RSSDP/SsdpDevice.cs
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Text;
-using System.Threading.Tasks;
-using System.Xml;
using Rssdp.Infrastructure;
namespace Rssdp
diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs
index e17e14c1a..59a2710d5 100644
--- a/RSSDP/SsdpDeviceLocator.cs
+++ b/RSSDP/SsdpDeviceLocator.cs
@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
using System.Linq;
+using System.Net;
using System.Net.Http;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
namespace Rssdp.Infrastructure
{
@@ -213,7 +210,7 @@ namespace Rssdp.Infrastructure
/// Raises the <see cref="DeviceAvailable"/> event.
/// </summary>
/// <seealso cref="DeviceAvailable"/>
- protected virtual void OnDeviceAvailable(DiscoveredSsdpDevice device, bool isNewDevice, IpAddressInfo localIpAddress)
+ protected virtual void OnDeviceAvailable(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress)
{
if (this.IsDisposed) return;
@@ -295,7 +292,7 @@ namespace Rssdp.Infrastructure
#region Discovery/Device Add
- private void AddOrUpdateDiscoveredDevice(DiscoveredSsdpDevice device, IpAddressInfo localIpAddress)
+ private void AddOrUpdateDiscoveredDevice(DiscoveredSsdpDevice device, IPAddress localIpAddress)
{
bool isNewDevice = false;
lock (_Devices)
@@ -316,7 +313,7 @@ namespace Rssdp.Infrastructure
DeviceFound(device, isNewDevice, localIpAddress);
}
- private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IpAddressInfo localIpAddress)
+ private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress)
{
if (!NotificationTypeMatchesFilter(device)) return;
@@ -357,7 +354,7 @@ namespace Rssdp.Infrastructure
return _CommunicationsServer.SendMulticastMessage(message, null, cancellationToken);
}
- private void ProcessSearchResponseMessage(HttpResponseMessage message, IpAddressInfo localIpAddress)
+ private void ProcessSearchResponseMessage(HttpResponseMessage message, IPAddress localIpAddress)
{
if (!message.IsSuccessStatusCode) return;
@@ -378,7 +375,7 @@ namespace Rssdp.Infrastructure
}
}
- private void ProcessNotificationMessage(HttpRequestMessage message, IpAddressInfo localIpAddress)
+ private void ProcessNotificationMessage(HttpRequestMessage message, IPAddress localIpAddress)
{
if (String.Compare(message.Method.Method, "Notify", StringComparison.OrdinalIgnoreCase) != 0) return;
@@ -389,7 +386,7 @@ namespace Rssdp.Infrastructure
ProcessByeByeNotification(message);
}
- private void ProcessAliveNotification(HttpRequestMessage message, IpAddressInfo localIpAddress)
+ private void ProcessAliveNotification(HttpRequestMessage message, IPAddress localIpAddress)
{
var location = GetFirstHeaderUriValue("Location", message);
if (location != null)
diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs
index 921f33c21..7f3e56394 100644
--- a/RSSDP/SsdpDevicePublisher.cs
+++ b/RSSDP/SsdpDevicePublisher.cs
@@ -2,13 +2,10 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Net.Http;
-using System.Text;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
using MediaBrowser.Common.Net;
-using Rssdp;
namespace Rssdp.Infrastructure
{
@@ -199,7 +196,12 @@ namespace Rssdp.Infrastructure
}
}
- private void ProcessSearchRequest(string mx, string searchTarget, IpEndPointInfo remoteEndPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken)
+ private void ProcessSearchRequest(
+ string mx,
+ string searchTarget,
+ IPEndPoint remoteEndPoint,
+ IPAddress receivedOnlocalIpAddress,
+ CancellationToken cancellationToken)
{
if (String.IsNullOrEmpty(searchTarget))
{
@@ -258,7 +260,7 @@ namespace Rssdp.Infrastructure
foreach (var device in deviceList)
{
if (!_sendOnlyMatchedHost ||
- _networkManager.IsInSameSubnet(device.ToRootDevice().Address, remoteEndPoint.IpAddress, device.ToRootDevice().SubnetMask))
+ _networkManager.IsInSameSubnet(device.ToRootDevice().Address, remoteEndPoint.Address, device.ToRootDevice().SubnetMask))
{
SendDeviceSearchResponses(device, remoteEndPoint, receivedOnlocalIpAddress, cancellationToken);
}
@@ -276,7 +278,11 @@ namespace Rssdp.Infrastructure
return _Devices.Union(_Devices.SelectManyRecursive<SsdpDevice>((d) => d.Devices));
}
- private void SendDeviceSearchResponses(SsdpDevice device, IpEndPointInfo endPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken)
+ private void SendDeviceSearchResponses(
+ SsdpDevice device,
+ IPEndPoint endPoint,
+ IPAddress receivedOnlocalIpAddress,
+ CancellationToken cancellationToken)
{
bool isRootDevice = (device as SsdpRootDevice) != null;
if (isRootDevice)
@@ -296,7 +302,13 @@ namespace Rssdp.Infrastructure
return String.Format("{0}::{1}", udn, fullDeviceType);
}
- private async void SendSearchResponse(string searchTarget, SsdpDevice device, string uniqueServiceName, IpEndPointInfo endPoint, IpAddressInfo receivedOnlocalIpAddress, CancellationToken cancellationToken)
+ private async void SendSearchResponse(
+ string searchTarget,
+ SsdpDevice device,
+ string uniqueServiceName,
+ IPEndPoint endPoint,
+ IPAddress receivedOnlocalIpAddress,
+ CancellationToken cancellationToken)
{
var rootDevice = device.ToRootDevice();
@@ -333,7 +345,7 @@ namespace Rssdp.Infrastructure
//WriteTrace(String.Format("Sent search response to " + endPoint.ToString()), device);
}
- private bool IsDuplicateSearchRequest(string searchTarget, IpEndPointInfo endPoint)
+ private bool IsDuplicateSearchRequest(string searchTarget, IPEndPoint endPoint)
{
var isDuplicateRequest = false;
@@ -556,7 +568,7 @@ namespace Rssdp.Infrastructure
private class SearchRequest
{
- public IpEndPointInfo EndPoint { get; set; }
+ public IPEndPoint EndPoint { get; set; }
public DateTime Received { get; set; }
public string SearchTarget { get; set; }
diff --git a/RSSDP/SsdpRootDevice.cs b/RSSDP/SsdpRootDevice.cs
index d918b9040..0f2de7b15 100644
--- a/RSSDP/SsdpRootDevice.cs
+++ b/RSSDP/SsdpRootDevice.cs
@@ -1,9 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml;
-using Rssdp.Infrastructure;
-using MediaBrowser.Model.Net;
+using System.Net;
namespace Rssdp
{
@@ -56,12 +52,12 @@ namespace Rssdp
/// <summary>
/// Gets or sets the Address used to check if the received message from same interface with this device/tree. Required.
/// </summary>
- public IpAddressInfo Address { get; set; }
+ public IPAddress Address { get; set; }
/// <summary>
/// Gets or sets the SubnetMask used to check if the received message from same interface with this device/tree. Required.
/// </summary>
- public IpAddressInfo SubnetMask { get; set; }
+ public IPAddress SubnetMask { get; set; }
/// <summary>
/// The base URL to use for all relative url's provided in other propertise (and those of child devices). Optional.
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
index 1249a60c0..e7e02a7d5 100644
--- a/jellyfin.ruleset
+++ b/jellyfin.ruleset
@@ -27,6 +27,10 @@
<Rule Id="CA1031" Action="Info" />
<!-- disable warning CA1062: Validate arguments of public methods -->
<Rule Id="CA1062" Action="Info" />
+ <!-- disable warning CA1812: internal class that is apparently never instantiated.
+ If so, remove the code from the assembly.
+ If this class is intended to contain only static members, make it static -->
+ <Rule Id="CA1812" Action="Info" />
<!-- disable warning CA1822: Member does not access instance data and can be marked as static -->
<Rule Id="CA1822" Action="Info" />