From 9fa4cedb714bdde7e4e03494832740ece2c19df2 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Thu, 26 Sep 2013 21:41:08 -0700 Subject: [PATCH] Now checking for errors before parsing newznab feeds --- .../Files/Indexers/Newznab/error.xml | 2 ++ NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 2 +- .../Indexers/Exceptions/ApiKeyException.cs | 19 +++++++++++++++ NzbDrone.Core/Indexers/IndexerFetchService.cs | 13 ++++++---- .../Indexers/Newznab/NewznabException.cs | 19 +++++++++++++++ .../Indexers/Newznab/NewznabParser.cs | 7 ++++++ .../Indexers/Newznab/NewznabPreProcessor.cs | 24 +++++++++++++++++++ NzbDrone.Core/Indexers/NewznabTestService.cs | 22 ++++++++++------- NzbDrone.Core/Indexers/RssParserBase.cs | 6 +++++ NzbDrone.Core/NzbDrone.Core.csproj | 3 +++ UI/Settings/Indexers/EditView.js | 4 ++-- 11 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 NzbDrone.Core.Test/Files/Indexers/Newznab/error.xml create mode 100644 NzbDrone.Core/Indexers/Exceptions/ApiKeyException.cs create mode 100644 NzbDrone.Core/Indexers/Newznab/NewznabException.cs create mode 100644 NzbDrone.Core/Indexers/Newznab/NewznabPreProcessor.cs diff --git a/NzbDrone.Core.Test/Files/Indexers/Newznab/error.xml b/NzbDrone.Core.Test/Files/Indexers/Newznab/error.xml new file mode 100644 index 000000000..33e46d9b6 --- /dev/null +++ b/NzbDrone.Core.Test/Files/Indexers/Newznab/error.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 22ee553f8..99987c84b 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -252,6 +252,7 @@ Always + Always @@ -351,7 +352,6 @@ - diff --git a/NzbDrone.Core/Indexers/Exceptions/ApiKeyException.cs b/NzbDrone.Core/Indexers/Exceptions/ApiKeyException.cs new file mode 100644 index 000000000..ff97425f8 --- /dev/null +++ b/NzbDrone.Core/Indexers/Exceptions/ApiKeyException.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Indexers.Exceptions +{ + public class ApiKeyException : NzbDroneException + { + public ApiKeyException(string message, params object[] args) : base(message, args) + { + } + + public ApiKeyException(string message) : base(message) + { + } + } +} diff --git a/NzbDrone.Core/Indexers/IndexerFetchService.cs b/NzbDrone.Core/Indexers/IndexerFetchService.cs index 9814adc0d..ba284c8b7 100644 --- a/NzbDrone.Core/Indexers/IndexerFetchService.cs +++ b/NzbDrone.Core/Indexers/IndexerFetchService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Net; using NLog; using NzbDrone.Common; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser.Model; using System.Linq; @@ -30,7 +31,6 @@ namespace NzbDrone.Core.Indexers _logger = logger; } - public virtual IList FetchRss(IIndexer indexer) { _logger.Debug("Fetching feeds from " + indexer.Name); @@ -53,7 +53,6 @@ namespace NzbDrone.Core.Indexers return result; } - private IList Fetch(IIndexer indexer, SeasonSearchCriteria searchCriteria, int offset) { _logger.Debug("Searching for {0} offset: {1}", searchCriteria, offset); @@ -117,15 +116,21 @@ namespace NzbDrone.Core.Indexers } catch (WebException webException) { - if (webException.Message.Contains("502") || webException.Message.Contains("503") || webException.Message.Contains("timed out")) + if (webException.Message.Contains("502") || webException.Message.Contains("503") || + webException.Message.Contains("timed out")) { - _logger.Warn("{0} server is currently unavailable. {1} {2}", indexer.Name, url, webException.Message); + _logger.Warn("{0} server is currently unavailable. {1} {2}", indexer.Name, url, + webException.Message); } else { _logger.Warn("{0} {1} {2}", indexer.Name, url, webException.Message); } } + catch (ApiKeyException) + { + _logger.Warn("Invalid API Key for {0} {1}", indexer.Name, url); + } catch (Exception feedEx) { feedEx.Data.Add("FeedUrl", url); diff --git a/NzbDrone.Core/Indexers/Newznab/NewznabException.cs b/NzbDrone.Core/Indexers/Newznab/NewznabException.cs new file mode 100644 index 000000000..df858ac24 --- /dev/null +++ b/NzbDrone.Core/Indexers/Newznab/NewznabException.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Indexers.Newznab +{ + public class NewznabException : NzbDroneException + { + public NewznabException(string message, params object[] args) : base(message, args) + { + } + + public NewznabException(string message) : base(message) + { + } + } +} diff --git a/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs b/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs index fc9e54d93..bd8096877 100644 --- a/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs +++ b/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs @@ -1,6 +1,8 @@ using System; using System.Linq; +using System.Xml; using System.Xml.Linq; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Newznab @@ -46,5 +48,10 @@ namespace NzbDrone.Core.Indexers.Newznab return currentResult; } + + protected override void PreProcess(string source, string url) + { + NewznabPreProcessor.Process(source, url); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Indexers/Newznab/NewznabPreProcessor.cs b/NzbDrone.Core/Indexers/Newznab/NewznabPreProcessor.cs new file mode 100644 index 000000000..3977a2c75 --- /dev/null +++ b/NzbDrone.Core/Indexers/Newznab/NewznabPreProcessor.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq; +using System.Xml.Linq; +using NzbDrone.Core.Indexers.Exceptions; + +namespace NzbDrone.Core.Indexers.Newznab +{ + public static class NewznabPreProcessor + { + public static void Process(string source, string url) + { + var xdoc = XDocument.Parse(source); + var error = xdoc.Descendants("error").FirstOrDefault(); + + if (error == null) return; + + var code = Convert.ToInt32(error.Attribute("code").Value); + + if (code >= 100 && code <= 199) throw new ApiKeyException("Invalid API key: {0}"); + + throw new NewznabException("Newznab error detected: {0}", error.Attribute("description").Value); + } + } +} diff --git a/NzbDrone.Core/Indexers/NewznabTestService.cs b/NzbDrone.Core/Indexers/NewznabTestService.cs index dd5fea38c..c56b9b464 100644 --- a/NzbDrone.Core/Indexers/NewznabTestService.cs +++ b/NzbDrone.Core/Indexers/NewznabTestService.cs @@ -5,6 +5,8 @@ using FluentValidation; using FluentValidation.Results; using NLog; using NzbDrone.Common; +using NzbDrone.Core.Indexers.Exceptions; +using NzbDrone.Core.Indexers.Newznab; namespace NzbDrone.Core.Indexers { @@ -34,21 +36,25 @@ namespace NzbDrone.Core.Indexers try { - _httpProvider.DownloadString(indexer.RecentFeed.First()); + var url = indexer.RecentFeed.First(); + var xml = _httpProvider.DownloadString(url); + + NewznabPreProcessor.Process(xml, url); } + catch (ApiKeyException apiKeyException) + { + _logger.Warn("Indexer returned result for Newznab RSS URL, API Key appears to be invalid"); - catch (Exception) + var apiKeyFailure = new ValidationFailure("ApiKey", "Invalid API Key"); + throw new ValidationException(new List { apiKeyFailure }.ToArray()); + } + catch (Exception ex) { - _logger.Warn("No result returned from RSS Feed, please confirm you're using a newznab indexer"); + _logger.Warn("Indexer doesn't appear to be Newznab based"); var failure = new ValidationFailure("Url", "Invalid Newznab URL entered"); throw new ValidationException(new List { failure }.ToArray()); } - - _logger.Warn("Indexer returned result for Newznab RSS URL, API Key appears to be invalid"); - - var apiKeyFailure = new ValidationFailure("ApiKey", "Invalid API Key"); - throw new ValidationException(new List { apiKeyFailure }.ToArray()); } } } diff --git a/NzbDrone.Core/Indexers/RssParserBase.cs b/NzbDrone.Core/Indexers/RssParserBase.cs index ca4bf91f8..7eae9a117 100644 --- a/NzbDrone.Core/Indexers/RssParserBase.cs +++ b/NzbDrone.Core/Indexers/RssParserBase.cs @@ -29,6 +29,8 @@ namespace NzbDrone.Core.Indexers public IEnumerable Process(string xml, string url) { + PreProcess(xml, url); + using (var xmlTextReader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { ProhibitDtd = false, IgnoreComments = true })) { @@ -103,6 +105,10 @@ namespace NzbDrone.Core.Indexers protected abstract long GetSize(XElement item); + protected virtual void PreProcess(string source, string url) + { + } + protected virtual ReleaseInfo PostProcessor(XElement item, ReleaseInfo currentResult) { return currentResult; diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 205b6c817..34bc316bb 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -234,6 +234,7 @@ + @@ -241,6 +242,8 @@ + + diff --git a/UI/Settings/Indexers/EditView.js b/UI/Settings/Indexers/EditView.js index 0e4f227f2..4d0defee0 100644 --- a/UI/Settings/Indexers/EditView.js +++ b/UI/Settings/Indexers/EditView.js @@ -36,7 +36,7 @@ define( App.vent.trigger(App.Commands.CloseModalCommand); }); - promise.always(function () { + promise.fail(function () { self.ui.activity.empty(); }); } @@ -63,7 +63,7 @@ define( }); }); - promise.always(function () { + promise.fail(function () { self.ui.activity.empty(); }); }