diff options
Diffstat (limited to 'MediaBrowser.Common')
| -rw-r--r-- | MediaBrowser.Common/Extensions/HttpContextExtensions.cs | 56 | ||||
| -rw-r--r-- | MediaBrowser.Common/IApplicationHost.cs | 7 | ||||
| -rw-r--r-- | MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs | 44 | ||||
| -rw-r--r-- | MediaBrowser.Common/Json/JsonDefaults.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Common/MediaBrowser.Common.csproj | 10 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/DefaultHttpClientHandler.cs | 20 | ||||
| -rw-r--r-- | MediaBrowser.Common/Net/NamedClient.cs | 18 |
7 files changed, 148 insertions, 13 deletions
diff --git a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs index d746207c72..e0cf3f9ac3 100644 --- a/MediaBrowser.Common/Extensions/HttpContextExtensions.cs +++ b/MediaBrowser.Common/Extensions/HttpContextExtensions.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Services; +using System.Net; +using MediaBrowser.Common.Net; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Common.Extensions @@ -8,26 +9,55 @@ namespace MediaBrowser.Common.Extensions /// </summary> public static class HttpContextExtensions { - private const string ServiceStackRequest = "ServiceStackRequest"; - /// <summary> - /// Set the ServiceStack request. + /// Checks the origin of the HTTP request. /// </summary> - /// <param name="httpContext">The HttpContext instance.</param> - /// <param name="request">The service stack request instance.</param> - public static void SetServiceStackRequest(this HttpContext httpContext, IRequest request) + /// <param name="request">The incoming HTTP request.</param> + /// <returns><c>true</c> if the request is coming from LAN, <c>false</c> otherwise.</returns> + public static bool IsLocal(this HttpRequest request) { - httpContext.Items[ServiceStackRequest] = request; + return (request.HttpContext.Connection.LocalIpAddress == null + && request.HttpContext.Connection.RemoteIpAddress == null) + || request.HttpContext.Connection.LocalIpAddress.Equals(request.HttpContext.Connection.RemoteIpAddress); } /// <summary> - /// Get the ServiceStack request. + /// Extracts the remote IP address of the caller of the HTTP request. /// </summary> - /// <param name="httpContext">The HttpContext instance.</param> - /// <returns>The service stack request instance.</returns> - public static IRequest GetServiceStackRequest(this HttpContext httpContext) + /// <param name="request">The HTTP request.</param> + /// <returns>The remote caller IP address.</returns> + public static string RemoteIp(this HttpRequest request) { - return (IRequest)httpContext.Items[ServiceStackRequest]; + var cachedRemoteIp = request.HttpContext.Items["RemoteIp"]?.ToString(); + if (!string.IsNullOrEmpty(cachedRemoteIp)) + { + return cachedRemoteIp; + } + + IPAddress ip; + + // "Real" remote ip might be in X-Forwarded-For of X-Real-Ip + // (if the server is behind a reverse proxy for example) + if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XForwardedFor].ToString(), out ip)) + { + if (!IPAddress.TryParse(request.Headers[CustomHeaderNames.XRealIP].ToString(), out ip)) + { + ip = request.HttpContext.Connection.RemoteIpAddress; + + // Default to the loopback address if no RemoteIpAddress is specified (i.e. during integration tests) + ip ??= IPAddress.Loopback; + } + } + + if (ip.IsIPv4MappedToIPv6) + { + ip = ip.MapToIPv4(); + } + + var normalizedIp = ip.ToString(); + + request.HttpContext.Items["RemoteIp"] = normalizedIp; + return normalizedIp; } } } diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 7a76be7223..849037ac46 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; using System.Threading.Tasks; using MediaBrowser.Common.Plugins; using Microsoft.Extensions.DependencyInjection; @@ -77,6 +78,12 @@ namespace MediaBrowser.Common IReadOnlyList<IPlugin> Plugins { get; } /// <summary> + /// Gets all plugin assemblies which implement a custom rest api. + /// </summary> + /// <returns>An <see cref="IEnumerable{Assembly}"/> containing the plugin assemblies.</returns> + IEnumerable<Assembly> GetApiPluginAssemblies(); + + /// <summary> /// Notifies the pending restart. /// </summary> void NotifyPendingRestart(); diff --git a/MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs b/MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs new file mode 100644 index 0000000000..cffc41ba34 --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/JsonNullableStructConverter.cs @@ -0,0 +1,44 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// <summary> + /// Converts a nullable struct or value to/from JSON. + /// Required - some clients send an empty string. + /// </summary> + /// <typeparam name="T">The struct type.</typeparam> + public class JsonNullableStructConverter<T> : JsonConverter<T?> + where T : struct + { + private readonly JsonConverter<T?> _baseJsonConverter; + + /// <summary> + /// Initializes a new instance of the <see cref="JsonNullableStructConverter{T}"/> class. + /// </summary> + /// <param name="baseJsonConverter">The base json converter.</param> + public JsonNullableStructConverter(JsonConverter<T?> baseJsonConverter) + { + _baseJsonConverter = baseJsonConverter; + } + + /// <inheritdoc /> + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + // Handle empty string. + if (reader.TokenType == JsonTokenType.String && ((reader.HasValueSequence && reader.ValueSequence.IsEmpty) || reader.ValueSpan.IsEmpty)) + { + return null; + } + + return _baseJsonConverter.Read(ref reader, typeToConvert, options); + } + + /// <inheritdoc /> + public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) + { + _baseJsonConverter.Write(writer, value, options); + } + } +} diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs index 9d30927dbb..5867cd4a0c 100644 --- a/MediaBrowser.Common/Json/JsonDefaults.cs +++ b/MediaBrowser.Common/Json/JsonDefaults.cs @@ -29,8 +29,14 @@ namespace MediaBrowser.Common.Json NumberHandling = JsonNumberHandling.AllowReadingFromString }; + // Get built-in converters for fallback converting. + var baseNullableInt32Converter = (JsonConverter<int?>)options.GetConverter(typeof(int?)); + var baseNullableInt64Converter = (JsonConverter<long?>)options.GetConverter(typeof(long?)); + options.Converters.Add(new JsonGuidConverter()); options.Converters.Add(new JsonStringEnumConverter()); + options.Converters.Add(new JsonNullableStructConverter<int>(baseNullableInt32Converter)); + options.Converters.Add(new JsonNullableStructConverter<long>(baseNullableInt64Converter)); return options; } diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index e4bc93abc2..70dcc2397c 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -20,6 +20,7 @@ <ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.7" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.7" /> + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/> <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" /> </ItemGroup> @@ -32,6 +33,15 @@ <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> + <IncludeSymbols>true</IncludeSymbols> + <SymbolPackageFormat>snupkg</SymbolPackageFormat> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> + <!-- Include all symbols in the main nupkg until Azure Artifact Feed starts supporting ingesting NuGet symbol packages. --> + <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> </PropertyGroup> <!-- Code analyzers--> diff --git a/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs b/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs new file mode 100644 index 0000000000..e189d6e706 --- /dev/null +++ b/MediaBrowser.Common/Net/DefaultHttpClientHandler.cs @@ -0,0 +1,20 @@ +using System.Net; +using System.Net.Http; + +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Default http client handler. + /// </summary> + public class DefaultHttpClientHandler : HttpClientHandler + { + /// <summary> + /// Initializes a new instance of the <see cref="DefaultHttpClientHandler"/> class. + /// </summary> + public DefaultHttpClientHandler() + { + // TODO change to DecompressionMethods.All with .NET5 + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + } + } +} diff --git a/MediaBrowser.Common/Net/NamedClient.cs b/MediaBrowser.Common/Net/NamedClient.cs new file mode 100644 index 0000000000..0f6161c328 --- /dev/null +++ b/MediaBrowser.Common/Net/NamedClient.cs @@ -0,0 +1,18 @@ +namespace MediaBrowser.Common.Net +{ + /// <summary> + /// Registered http client names. + /// </summary> + public static class NamedClient + { + /// <summary> + /// Gets the value for the default named http client. + /// </summary> + public const string Default = nameof(Default); + + /// <summary> + /// Gets the value for the MusicBrainz named http client. + /// </summary> + public const string MusicBrainz = nameof(MusicBrainz); + } +} |
