[TrackerIcon] Use httpdownloader page redirect handling

User reported infinite redirecting when attempting to fetch tracker
icon.

Fixed by allowing httpdownloader and RedirectAgent to handle page
redirects including catching infinite redirects

Trac: https://dev.deluge-torrent.org/ticket/3167
See-also: https://github.com/twisted/twisted/blob/5c24e9/src/twisted/web/client.py#L168
This commit is contained in:
Calum Lind 2022-04-30 17:40:29 +01:00
parent 61a83bbd20
commit 96a0825add
No known key found for this signature in database
GPG Key ID: 90597A687B836BA3
1 changed files with 13 additions and 44 deletions

View File

@ -13,7 +13,7 @@ from tempfile import mkstemp
from urllib.parse import urljoin, urlparse from urllib.parse import urljoin, urlparse
from twisted.internet import defer, threads from twisted.internet import defer, threads
from twisted.web.error import PageRedirect from twisted.python.failure import Failure
from twisted.web.resource import ForbiddenResource, NoResource from twisted.web.resource import ForbiddenResource, NoResource
from deluge.component import Component from deluge.component import Component
@ -208,7 +208,6 @@ class TrackerIcons(Component):
d.addCallbacks( d.addCallbacks(
self.on_download_page_complete, self.on_download_page_complete,
self.on_download_page_fail, self.on_download_page_fail,
errbackArgs=(host,),
) )
d.addCallback(self.parse_html_page) d.addCallback(self.parse_html_page)
d.addCallbacks( d.addCallbacks(
@ -242,7 +241,7 @@ class TrackerIcons(Component):
log.debug('Downloading %s %s', host, url) log.debug('Downloading %s %s', host, url)
tmp_fd, tmp_file = mkstemp(prefix='deluge_ticon.') tmp_fd, tmp_file = mkstemp(prefix='deluge_ticon.')
os.close(tmp_fd) os.close(tmp_fd)
return download_file(url, tmp_file, force_filename=True, handle_redirects=False) return download_file(url, tmp_file, force_filename=True)
def on_download_page_complete(self, page): def on_download_page_complete(self, page):
""" """
@ -256,33 +255,18 @@ class TrackerIcons(Component):
log.debug('Finished downloading %s', page) log.debug('Finished downloading %s', page)
return page return page
def on_download_page_fail(self, f, host): def on_download_page_fail(self, failure: 'Failure') -> 'Failure':
""" """Runs any download failure clean-up functions
Recovers from download error
:param f: the failure that occurred Args:
:type f: Failure failure: The failure that occurred.
:param host: the name of the host whose page failed to download
:type host: string
:returns: a Deferred if recovery was possible
else the original failure
:rtype: Deferred or Failure
"""
error_msg = f.getErrorMessage()
log.debug('Error downloading page: %s', error_msg)
d = f
if f.check(PageRedirect):
# Handle redirect errors
location = urljoin(self.host_to_url(host), error_msg.split(' to ')[1])
self.redirects[host] = url_to_host(location)
d = self.download_page(host, url=location)
d.addCallbacks(
self.on_download_page_complete,
self.on_download_page_fail,
errbackArgs=(host,),
)
return d Returns:
The original failure.
"""
log.debug(f'Error downloading page: {failure.getErrorMessage()}')
return failure
@proxy(threads.deferToThread) @proxy(threads.deferToThread)
def parse_html_page(self, page): def parse_html_page(self, page):
@ -425,22 +409,7 @@ class TrackerIcons(Component):
error_msg = f.getErrorMessage() error_msg = f.getErrorMessage()
log.debug('Error downloading icon from %s: %s', host, error_msg) log.debug('Error downloading icon from %s: %s', host, error_msg)
d = f d = f
if f.check(PageRedirect): if f.check(NoResource, ForbiddenResource) and icons:
# Handle redirect errors
location = urljoin(self.host_to_url(host), error_msg.split(' to ')[1])
d = self.download_icon(
[(location, extension_to_mimetype(location.rpartition('.')[2]))]
+ icons,
host,
)
if not icons:
d.addCallbacks(
self.on_download_icon_complete,
self.on_download_icon_fail,
callbackArgs=(host,),
errbackArgs=(host,),
)
elif f.check(NoResource, ForbiddenResource) and icons:
d = self.download_icon(icons, host) d = self.download_icon(icons, host)
elif f.check(NoIconsError): elif f.check(NoIconsError):
# No icons, try favicon.ico as an act of desperation # No icons, try favicon.ico as an act of desperation