diff --git a/sopel/plugins/rules.py b/sopel/plugins/rules.py index 142ee9ffb7..6abb1157b9 100644 --- a/sopel/plugins/rules.py +++ b/sopel/plugins/rules.py @@ -1678,14 +1678,16 @@ def match(self, bot, pretrigger): if not self.match_preconditions(bot, pretrigger): return - urls = ( - url - for url in pretrigger.urls - if urlparse(url).scheme in self._schemes - ) + # Parse only valid URLs with wanted schemes + for url in pretrigger.urls: + try: + if urlparse(url).scheme not in self._schemes: + # skip URLs with unwanted scheme + continue + except ValueError: + # skip invalid URLs + continue - # Parse URL for each found - for url in urls: # TODO: convert to 'yield from' when dropping Python 2.7 for result in self.parse(url): yield result diff --git a/test/plugins/test_plugins_rules.py b/test/plugins/test_plugins_rules.py index 3919fd1704..9d019a0cbb 100644 --- a/test/plugins/test_plugins_rules.py +++ b/test/plugins/test_plugins_rules.py @@ -2609,13 +2609,27 @@ def test_url_callback_parse(): re.escape('https://wikipedia.com/') + r'(\w+)' ) - rule = rules.SearchRule([regex]) + rule = rules.URLCallback([regex]) results = list(rule.parse('https://wikipedia.com/something')) assert len(results) == 1, 'URLCallback on word must match only once' assert results[0].group(0) == 'https://wikipedia.com/something' assert results[0].group(1) == 'something' +def test_url_callback_match(mockbot): + regex = re.compile(r'.*') + rule = rules.URLCallback([regex]) + + line = ( + ':Foo!foo@example.com PRIVMSG #sopel :' + 'two links http://example.com one invalid https://[dfdsdfsdf' + ) + pretrigger = trigger.PreTrigger(mockbot.nick, line) + matches = list(rule.match(mockbot, pretrigger)) + assert len(matches) == 1, 'URLCallback must ignore invalid URLs' + assert matches[0].group(0) == 'http://example.com' + + def test_url_callback_execute(mockbot): regex = re.compile(r'.*') rule = rules.URLCallback([regex])