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

ref #2802
pull/3718/head
Taloth Saldono 5 years ago committed by Qstick
parent ae47ee817f
commit 895abe8c3b

@ -2,9 +2,13 @@ using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Reflection;
using NLog;
using NLog.Fluent;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Proxy;
using NzbDrone.Common.Instrumentation.Extensions;
namespace NzbDrone.Common.Http.Dispatchers
{
@ -13,12 +17,16 @@ namespace NzbDrone.Common.Http.Dispatchers
private readonly IHttpProxySettingsProvider _proxySettingsProvider;
private readonly ICreateManagedWebProxy _createManagedWebProxy;
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;
_createManagedWebProxy = createManagedWebProxy;
_userAgentBuilder = userAgentBuilder;
_platformInfo = platformInfo;
_logger = logger;
}
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
@ -38,7 +46,7 @@ namespace NzbDrone.Common.Http.Dispatchers
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
}
webRequest.Method = request.Method.ToString();
webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
webRequest.KeepAlive = request.ConnectionKeepAlive;
@ -78,6 +86,9 @@ namespace NzbDrone.Common.Http.Dispatchers
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.
if (e.Status == WebExceptionStatus.NameResolutionFailure)
{
@ -192,5 +203,35 @@ namespace NzbDrone.Common.Http.Dispatchers
}
}
}
// 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();
}
}
}
}
}

@ -30,8 +30,8 @@ namespace NzbDrone.Core.Test.Framework
Mocker.SetConstant<IHttpProxySettingsProvider>(new HttpProxySettingsProvider(Mocker.Resolve<ConfigService>()));
Mocker.SetConstant<ICreateManagedWebProxy>(new ManagedWebProxyFactory(Mocker.Resolve<CacheManager>()));
Mocker.SetConstant<ManagedHttpDispatcher>(new ManagedHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<ICreateManagedWebProxy>(), Mocker.Resolve<UserAgentBuilder>()));
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<UserAgentBuilder>(), Mocker.Resolve<NLog.Logger>()));
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>(), 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<IRadarrCloudRequestBuilder>(new RadarrCloudRequestBuilder());

Loading…
Cancel
Save