From b19d66581716d97e79de2ed52672ed1feed4e985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D1=82=D1=80=20=D0=A8=D1=83=D1=80=D0=B3=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=BD?= Date: Thu, 16 Jan 2020 13:38:26 +0300 Subject: [PATCH] Fixed: RestClient does not use global proxy settings --- .../Http/Proxy/IHttpProxySettingsProvider.cs | 1 + .../Http/HttpProxySettingsProvider.cs | 29 ++++++++++++------- .../Notifications/Boxcar/BoxcarProxy.cs | 6 ++-- .../Notifications/Gotify/GotifyProxy.cs | 9 +++++- .../Notifications/Join/JoinProxy.cs | 12 ++++---- .../PushBullet/PushBulletProxy.cs | 8 +++-- .../Notifications/Pushover/PushoverProxy.cs | 6 ++-- .../Notifications/Telegram/TelegramService.cs | 16 ++++++---- .../Notifications/Xbmc/XbmcJsonApiProxy.cs | 6 ++-- src/NzbDrone.Core/Rest/IRestClientFactory.cs | 9 ++++++ src/NzbDrone.Core/Rest/RestClientFactory.cs | 19 ++++++++++-- 11 files changed, 88 insertions(+), 33 deletions(-) create mode 100644 src/NzbDrone.Core/Rest/IRestClientFactory.cs diff --git a/src/NzbDrone.Common/Http/Proxy/IHttpProxySettingsProvider.cs b/src/NzbDrone.Common/Http/Proxy/IHttpProxySettingsProvider.cs index a288a46c4..bb5909395 100644 --- a/src/NzbDrone.Common/Http/Proxy/IHttpProxySettingsProvider.cs +++ b/src/NzbDrone.Common/Http/Proxy/IHttpProxySettingsProvider.cs @@ -3,5 +3,6 @@ namespace NzbDrone.Common.Http.Proxy public interface IHttpProxySettingsProvider { HttpProxySettings GetProxySettings(HttpRequest request); + HttpProxySettings GetProxySettings(); } } diff --git a/src/NzbDrone.Core/Http/HttpProxySettingsProvider.cs b/src/NzbDrone.Core/Http/HttpProxySettingsProvider.cs index 6e5a23e07..6c335abae 100644 --- a/src/NzbDrone.Core/Http/HttpProxySettingsProvider.cs +++ b/src/NzbDrone.Core/Http/HttpProxySettingsProvider.cs @@ -17,18 +17,9 @@ namespace NzbDrone.Core.Http public HttpProxySettings GetProxySettings(HttpRequest request) { - if (!_configService.ProxyEnabled) - { + var proxySettings = GetProxySettings(); + if (proxySettings == null) return null; - } - - var proxySettings = new HttpProxySettings(_configService.ProxyType, - _configService.ProxyHostname, - _configService.ProxyPort, - _configService.ProxyBypassFilter, - _configService.ProxyBypassLocalAddresses, - _configService.ProxyUsername, - _configService.ProxyPassword); if (ShouldProxyBeBypassed(proxySettings, request.Url)) { @@ -38,6 +29,22 @@ namespace NzbDrone.Core.Http return proxySettings; } + public HttpProxySettings GetProxySettings() + { + if (!_configService.ProxyEnabled) + { + return null; + } + + return new HttpProxySettings(_configService.ProxyType, + _configService.ProxyHostname, + _configService.ProxyPort, + _configService.ProxyBypassFilter, + _configService.ProxyBypassLocalAddresses, + _configService.ProxyUsername, + _configService.ProxyPassword); + } + public bool ShouldProxyBeBypassed(HttpProxySettings proxySettings, HttpUri url) { //We are utilising the WebProxy implementation here to save us having to reimplement it. This way we use Microsofts implementation diff --git a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs index d4028d595..2d61b7467 100644 --- a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs +++ b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs @@ -16,11 +16,13 @@ namespace NzbDrone.Core.Notifications.Boxcar public class BoxcarProxy : IBoxcarProxy { + private readonly IRestClientFactory _restClientFactory; private readonly Logger _logger; private const string URL = "https://new.boxcar.io/api/notifications"; - public BoxcarProxy(Logger logger) + public BoxcarProxy(IRestClientFactory restClientFactory, Logger logger) { + _restClientFactory = restClientFactory; _logger = logger; } @@ -71,7 +73,7 @@ namespace NzbDrone.Core.Notifications.Boxcar { try { - var client = RestClientFactory.BuildClient(URL); + var client = _restClientFactory.BuildClient(URL); request.AddParameter("user_credentials", settings.Token); request.AddParameter("notification[title]", title); diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs index b14b530d3..3aed74304 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifyProxy.cs @@ -10,9 +10,16 @@ namespace NzbDrone.Core.Notifications.Gotify public class GotifyProxy : IGotifyProxy { + private readonly IRestClientFactory _restClientFactory; + + public GotifyProxy(IRestClientFactory restClientFactory) + { + _restClientFactory = restClientFactory; + } + public void SendNotification(string title, string message, GotifySettings settings) { - var client = RestClientFactory.BuildClient(settings.Server); + var client = _restClientFactory.BuildClient(settings.Server); var request = new RestRequest("message", Method.POST); request.AddQueryParameter("token", settings.AppToken); diff --git a/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs b/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs index c8d8bed6c..37da514be 100644 --- a/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs +++ b/src/NzbDrone.Core/Notifications/Join/JoinProxy.cs @@ -16,11 +16,13 @@ namespace NzbDrone.Core.Notifications.Join public class JoinProxy : IJoinProxy { + private readonly IRestClientFactory _restClientFactory; private readonly Logger _logger; private const string URL = "https://joinjoaomgcd.appspot.com/_ah/api/messaging/v1/sendPush?"; - public JoinProxy(Logger logger) + public JoinProxy(IRestClientFactory restClientFactory, Logger logger) { + _restClientFactory = restClientFactory; _logger = logger; } @@ -49,7 +51,7 @@ namespace NzbDrone.Core.Notifications.Join SendNotification(title, body, settings); return null; } - catch(JoinInvalidDeviceException ex) + catch (JoinInvalidDeviceException ex) { _logger.Error(ex, "Unable to send test Join message. Invalid Device IDs supplied."); return new ValidationFailure("DeviceIds", "Device IDs appear invalid."); @@ -59,7 +61,7 @@ namespace NzbDrone.Core.Notifications.Join _logger.Error(ex, "Unable to send test Join message."); return new ValidationFailure("ApiKey", ex.Message); } - catch(RestException ex) + catch (RestException ex) { _logger.Error(ex, "Unable to send test Join message. Server connection failed."); return new ValidationFailure("ApiKey", "Unable to connect to Join API. Please try again later."); @@ -74,7 +76,7 @@ namespace NzbDrone.Core.Notifications.Join private void SendNotification(string title, string message, RestRequest request, JoinSettings settings) { - var client = RestClientFactory.BuildClient(URL); + var client = _restClientFactory.BuildClient(URL); if (settings.DeviceNames.IsNotNullOrWhiteSpace()) { @@ -88,7 +90,7 @@ namespace NzbDrone.Core.Notifications.Join { request.AddParameter("deviceId", "group.all"); } - + request.AddParameter("apikey", settings.ApiKey); request.AddParameter("title", title); request.AddParameter("text", message); diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs index dcc94a116..d916225e0 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBulletProxy.cs @@ -21,12 +21,14 @@ namespace NzbDrone.Core.Notifications.PushBullet public class PushBulletProxy : IPushBulletProxy { + private readonly IRestClientFactory _restClientFactory; private readonly Logger _logger; private const string PUSH_URL = "https://api.pushbullet.com/v2/pushes"; private const string DEVICE_URL = "https://api.pushbullet.com/v2/devices"; - public PushBulletProxy(Logger logger) + public PushBulletProxy(IRestClientFactory restClientFactory, Logger logger) { + _restClientFactory = restClientFactory; _logger = logger; } @@ -96,7 +98,7 @@ namespace NzbDrone.Core.Notifications.PushBullet { try { - var client = RestClientFactory.BuildClient(DEVICE_URL); + var client = _restClientFactory.BuildClient(DEVICE_URL); var request = new RestRequest(Method.GET); client.Authenticator = new HttpBasicAuthenticator(settings.ApiKey, string.Empty); @@ -175,7 +177,7 @@ namespace NzbDrone.Core.Notifications.PushBullet { try { - var client = RestClientFactory.BuildClient(PUSH_URL); + var client = _restClientFactory.BuildClient(PUSH_URL); request.AddParameter("type", "note"); request.AddParameter("title", title); diff --git a/src/NzbDrone.Core/Notifications/Pushover/PushoverProxy.cs b/src/NzbDrone.Core/Notifications/Pushover/PushoverProxy.cs index d032220eb..81139377a 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/PushoverProxy.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/PushoverProxy.cs @@ -15,17 +15,19 @@ namespace NzbDrone.Core.Notifications.Pushover public class PushoverProxy : IPushoverProxy { + private readonly IRestClientFactory _restClientFactory; private readonly Logger _logger; private const string URL = "https://api.pushover.net/1/messages.json"; - public PushoverProxy(Logger logger) + public PushoverProxy(IRestClientFactory restClientFactory, Logger logger) { + _restClientFactory = restClientFactory; _logger = logger; } public void SendNotification(string title, string message, PushoverSettings settings) { - var client = RestClientFactory.BuildClient(URL); + var client = _restClientFactory.BuildClient(URL); var request = new RestRequest(Method.POST); request.AddParameter("token", settings.ApiKey); request.AddParameter("user", settings.UserKey); diff --git a/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs b/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs index 35f2193d5..4aaaee99c 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs @@ -4,6 +4,7 @@ using FluentValidation.Results; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Common.Serializer; +using NzbDrone.Common.Http.Proxy; using RestSharp; using NzbDrone.Core.Rest; using System.Web; @@ -18,11 +19,13 @@ namespace NzbDrone.Core.Notifications.Telegram public class TelegramProxy : ITelegramProxy { + private readonly IRestClientFactory _restClientFactory; private readonly Logger _logger; private const string URL = "https://api.telegram.org"; - public TelegramProxy(Logger logger) + public TelegramProxy(IRestClientFactory restClientFactory, Logger logger) { + _restClientFactory = restClientFactory; _logger = logger; } @@ -30,7 +33,8 @@ namespace NzbDrone.Core.Notifications.Telegram { //Format text to add the title before and bold using markdown var text = $"{HttpUtility.HtmlEncode(title)}\n{HttpUtility.HtmlEncode(message)}"; - var client = RestClientFactory.BuildClient(URL); + var client = _restClientFactory.BuildClient(URL); + var request = new RestRequest("bot{token}/sendmessage", Method.POST); request.AddUrlSegment("token", settings.BotToken); @@ -54,9 +58,11 @@ namespace NzbDrone.Core.Notifications.Telegram { _logger.Error(ex, "Unable to send test message"); - var restException = ex as RestException; - - if (restException != null && restException.Response.StatusCode == HttpStatusCode.BadRequest) + if (ex is WebException webException) + { + return new ValidationFailure("Connection", $"{webException.Status.ToString()}: {webException.Message}"); + } + else if (ex is RestException restException && restException.Response.StatusCode == HttpStatusCode.BadRequest) { var error = Json.Deserialize(restException.Response.Content); var property = error.Description.ContainsIgnoreCase("chat not found") ? "ChatId" : "BotToken"; diff --git a/src/NzbDrone.Core/Notifications/Xbmc/XbmcJsonApiProxy.cs b/src/NzbDrone.Core/Notifications/Xbmc/XbmcJsonApiProxy.cs index 37040ad1d..f3db41132 100644 --- a/src/NzbDrone.Core/Notifications/Xbmc/XbmcJsonApiProxy.cs +++ b/src/NzbDrone.Core/Notifications/Xbmc/XbmcJsonApiProxy.cs @@ -21,10 +21,12 @@ namespace NzbDrone.Core.Notifications.Xbmc public class XbmcJsonApiProxy : IXbmcJsonApiProxy { + private readonly IRestClientFactory _restClientFactory; private readonly Logger _logger; - public XbmcJsonApiProxy(Logger logger) + public XbmcJsonApiProxy(IRestClientFactory restClientFactory, Logger logger) { + _restClientFactory = restClientFactory; _logger = logger; } @@ -110,7 +112,7 @@ namespace NzbDrone.Core.Notifications.Xbmc private IRestClient BuildClient(XbmcSettings settings) { var url = string.Format(@"http://{0}/jsonrpc", settings.Address); - var client = RestClientFactory.BuildClient(url); + var client = _restClientFactory.BuildClient(url); if (!settings.Username.IsNullOrWhiteSpace()) { diff --git a/src/NzbDrone.Core/Rest/IRestClientFactory.cs b/src/NzbDrone.Core/Rest/IRestClientFactory.cs new file mode 100644 index 000000000..39754016d --- /dev/null +++ b/src/NzbDrone.Core/Rest/IRestClientFactory.cs @@ -0,0 +1,9 @@ +using RestSharp; + +namespace NzbDrone.Core.Rest +{ + public interface IRestClientFactory + { + RestClient BuildClient(string baseUrl); + } +} diff --git a/src/NzbDrone.Core/Rest/RestClientFactory.cs b/src/NzbDrone.Core/Rest/RestClientFactory.cs index cc657c4b6..6197f09ba 100644 --- a/src/NzbDrone.Core/Rest/RestClientFactory.cs +++ b/src/NzbDrone.Core/Rest/RestClientFactory.cs @@ -1,17 +1,32 @@ using RestSharp; using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Http.Proxy; namespace NzbDrone.Core.Rest { - public static class RestClientFactory + public class RestClientFactory : IRestClientFactory { - public static RestClient BuildClient(string baseUrl) + private readonly IHttpProxySettingsProvider _httpProxySettingsProvider; + private readonly ICreateManagedWebProxy _createManagedWebProxy; + + public RestClientFactory(IHttpProxySettingsProvider httpProxySettingsProvider, ICreateManagedWebProxy createManagedWebProxy) + { + _httpProxySettingsProvider = httpProxySettingsProvider; + _createManagedWebProxy = createManagedWebProxy; + } + + public RestClient BuildClient(string baseUrl) { var restClient = new RestClient(baseUrl) { UserAgent = $"{BuildInfo.AppName}/{BuildInfo.Version} ({OsInfo.Os})" }; + var proxySettings = _httpProxySettingsProvider.GetProxySettings(); + if (proxySettings != null) + { + restClient.Proxy = _createManagedWebProxy.GetWebProxy(proxySettings); + } return restClient; }