1
0
Fork 0
mirror of https://github.com/Radarr/Radarr synced 2024-12-27 02:09:59 +00:00

Fixed: Workaround for mono 5.16+ bug preventing the closure of sockets on timeouts (Jackett connections)

ref #2802
This commit is contained in:
Taloth Saldono 2019-06-30 12:41:34 +02:00 committed by Qstick
parent ae47ee817f
commit 895abe8c3b
2 changed files with 45 additions and 4 deletions

View file

@ -2,9 +2,13 @@
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Net; using System.Net;
using System.Reflection;
using NLog;
using NLog.Fluent;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Proxy; using NzbDrone.Common.Http.Proxy;
using NzbDrone.Common.Instrumentation.Extensions;
namespace NzbDrone.Common.Http.Dispatchers namespace NzbDrone.Common.Http.Dispatchers
{ {
@ -13,12 +17,16 @@ public class ManagedHttpDispatcher : IHttpDispatcher
private readonly IHttpProxySettingsProvider _proxySettingsProvider; private readonly IHttpProxySettingsProvider _proxySettingsProvider;
private readonly ICreateManagedWebProxy _createManagedWebProxy; private readonly ICreateManagedWebProxy _createManagedWebProxy;
private readonly IUserAgentBuilder _userAgentBuilder; private readonly IUserAgentBuilder _userAgentBuilder;
private readonly IPlatformInfo _platformInfo;
private readonly Logger _logger;
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder) public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy, IUserAgentBuilder userAgentBuilder, IPlatformInfo platformInfo, Logger logger)
{ {
_proxySettingsProvider = proxySettingsProvider; _proxySettingsProvider = proxySettingsProvider;
_createManagedWebProxy = createManagedWebProxy; _createManagedWebProxy = createManagedWebProxy;
_userAgentBuilder = userAgentBuilder; _userAgentBuilder = userAgentBuilder;
_platformInfo = platformInfo;
_logger = logger;
} }
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies) public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
@ -78,6 +86,9 @@ public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
if (httpWebResponse == null) if (httpWebResponse == null)
{ {
// Workaround for mono not closing connections properly in certain situations.
AbortWebRequest(webRequest);
// The default messages for WebException on mono are pretty horrible. // The default messages for WebException on mono are pretty horrible.
if (e.Status == WebExceptionStatus.NameResolutionFailure) if (e.Status == WebExceptionStatus.NameResolutionFailure)
{ {
@ -192,5 +203,35 @@ protected virtual void AddRequestHeaders(HttpWebRequest webRequest, HttpHeader h
} }
} }
} }
// Workaround for mono not closing connections properly on timeouts
private void AbortWebRequest(HttpWebRequest webRequest)
{
// First affected version was mono 5.16
if (OsInfo.IsNotWindows && _platformInfo.Version >= new Version(5, 16))
{
try
{
var currentOperationInfo = webRequest.GetType().GetField("currentOperation", BindingFlags.NonPublic | BindingFlags.Instance);
var currentOperation = currentOperationInfo.GetValue(webRequest);
if (currentOperation != null)
{
var responseStreamInfo = currentOperation.GetType().GetField("responseStream", BindingFlags.NonPublic | BindingFlags.Instance);
var responseStream = responseStreamInfo.GetValue(currentOperation) as Stream;
// Note that responseStream will likely be null once mono fixes it.
responseStream?.Dispose();
}
}
catch (Exception ex)
{
// This can fail randomly on future mono versions that have been changed/fixed. Log to sentry and ignore.
_logger.Trace()
.Exception(ex)
.Message("Unable to dispose responseStream on mono {0}", _platformInfo.Version)
.Write();
}
}
}
} }
} }

View file

@ -30,8 +30,8 @@ protected void UseRealHttp()
Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>())); Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>()));
Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>())); Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>()));
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>())); Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<IPlatformInfo>(), TestLogger));
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<NLog.Logger>())); Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), TestLogger));
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger)); Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<FallbackHttpDispatcher>(), Mocker.Resolve<UserAgentBuilder>(), TestLogger)); Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<FallbackHttpDispatcher>(), Mocker.Resolve<UserAgentBuilder>(), TestLogger));
Mocker.SetConstant<IRadarrCloudRequestBuilder>(new RadarrCloudRequestBuilder()); Mocker.SetConstant<IRadarrCloudRequestBuilder>(new RadarrCloudRequestBuilder());