-
Notifications
You must be signed in to change notification settings - Fork 203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fall back to downloading using the requests Python package (if installed) when urllib2 fails due to SSL error #2538
Changes from all commits
0707acc
bfbe870
30575a6
d57140a
42390f3
0a8b774
62ceb23
fb3885f
5e2ea6d
06aad39
44669b0
5517ad3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,11 @@ | |
from easybuild.tools.config import build_option | ||
from easybuild.tools import run | ||
|
||
try: | ||
import requests | ||
HAVE_REQUESTS = True | ||
except ImportError: | ||
HAVE_REQUESTS = False | ||
|
||
_log = fancylogger.getLogger('filetools', fname=False) | ||
|
||
|
@@ -460,26 +465,47 @@ def download_file(filename, url, path, forced=False): | |
attempt_cnt = 0 | ||
|
||
# use custom HTTP header | ||
url_req = urllib2.Request(url, headers={'User-Agent': 'EasyBuild', "Accept" : "*/*"}) | ||
headers = {'User-Agent': 'EasyBuild', 'Accept': '*/*'} | ||
# for backward compatibility, and to avoid relying on 3rd party Python library 'requests' | ||
url_req = urllib2.Request(url, headers=headers) | ||
used_urllib = urllib2 | ||
|
||
while not downloaded and attempt_cnt < max_attempts: | ||
try: | ||
# urllib2 does the right thing for http proxy setups, urllib does not! | ||
url_fd = urllib2.urlopen(url_req, timeout=timeout) | ||
_log.debug('response code for given url %s: %s' % (url, url_fd.getcode())) | ||
if used_urllib is urllib2: | ||
# urllib2 does the right thing for http proxy setups, urllib does not! | ||
url_fd = urllib2.urlopen(url_req, timeout=timeout) | ||
status_code = url_fd.getcode() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bartoldeman add status_code = url_fd.getcode().code or maybe with if hasattr(status_code, 'code'):
status_code = status_code.code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How can that work? .code is a field of the exception err. for urllib2, and getcode() returns an integer. One can use
but I prefer to use use_urllib2 then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I'm not sure what I was smoking here, I was clearly mixing things up. Thanks for clarifying. |
||
else: | ||
response = requests.get(url, headers=headers, stream=True, timeout=timeout) | ||
status_code = response.status_code | ||
response.raise_for_status() | ||
url_fd = response.raw | ||
url_fd.decode_content = True | ||
_log.debug('response code for given url %s: %s' % (url, status_code)) | ||
write_file(path, url_fd.read(), forced=forced, backup=True) | ||
_log.info("Downloaded file %s from url %s to %s" % (filename, url, path)) | ||
downloaded = True | ||
url_fd.close() | ||
except urllib2.HTTPError as err: | ||
if 400 <= err.code <= 499: | ||
_log.warning("URL %s was not found (HTTP response code %s), not trying again" % (url, err.code)) | ||
except used_urllib.HTTPError as err: | ||
if used_urllib is urllib2: | ||
status_code = err.code | ||
if 400 <= status_code <= 499: | ||
_log.warning("URL %s was not found (HTTP response code %s), not trying again" % (url, status_code)) | ||
break | ||
else: | ||
_log.warning("HTTPError occurred while trying to download %s to %s: %s" % (url, path, err)) | ||
attempt_cnt += 1 | ||
except IOError as err: | ||
_log.warning("IOError occurred while trying to download %s to %s: %s" % (url, path, err)) | ||
error_re = re.compile(r"<urlopen error \[Errno 1\] _ssl.c:.*: error:.*:" | ||
"SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure>") | ||
if error_re.match(str(err)): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This construct is used to switch to trying with # for backward compatibility, and to avoid relying on 3rd party Python library 'requests'
use_requests = False
while not downloaded and attempt_cnt < max_attempts:
if use_requests:
if not HAVE_REQUESTS:
raise EasyBuildError("...")
# do requests...
else:
# do what we do now
try:
...
except IOError as err:
if error_re.match(str(err)):
use_requests = True |
||
if not HAVE_REQUESTS: | ||
raise EasyBuildError("SSL issues with urllib2. If you are using RHEL/CentOS 6.x please " | ||
"install the python-requests and pyOpenSSL RPM packages and try again.") | ||
_log.info("Downloading using requests package instead of urllib2") | ||
used_urllib = requests | ||
attempt_cnt += 1 | ||
except Exception, err: | ||
raise EasyBuildError("Unexpected error occurred when trying to download %s to %s: %s", url, path, err) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bartoldeman I'd prefer using a boolean here (
use_urllib2
) and handlingHTTPError
via theimport
aboveThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot
from requests.exceptions import HTTPError
before it is actually used (because at the first download attemptHTTPError
is stillurllib.HTTPError
, that is whyI changed to
used_urllib
. If I do both:that's a bit double...
Perhaps I should just write a
urlopen()
emulation using requests (including raising the urllib2.HTTPError exception manually), which might be the cleanest then.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I overlooked that you first need
HTTPError
fromurllib2
...