1
2
3
4 import sys, os, socket, ssl
5
6 from zeroinstall import _
7 from zeroinstall.injector import download
8 from zeroinstall.support import ssl_match_hostname
9
10 if sys.version_info[0] > 2:
11 from urllib import request as urllib2
12 from http.client import HTTPSConnection, HTTPException
13 else:
14 import urllib2
15 from httplib import HTTPSConnection, HTTPException
16
17 try:
18
19 import certifi
20 _fallback_ca_bundle = certifi.where()
21 except:
22
23 _fallback_ca_bundle = os.path.join(os.path.dirname(__file__), "EquifaxSecureCA.crt")
24
25
26
27
28 for ca_bundle in [
29 "/etc/ssl/certs/ca-certificates.crt",
30 "/etc/pki/tls/certs/ca-bundle.crt",
31 "/etc/ssl/ca-bundle.pem",
32 "/var/lib/ca-certificates/ca-bundle.pem.new",
33 _fallback_ca_bundle]:
34 if os.path.exists(ca_bundle):
37 sock = socket.create_connection((self.host, self.port), self.timeout)
38 if hasattr(self, '_tunnel_host') and self._tunnel_host:
39 self.sock = sock
40 self._tunnel()
41 sock = ssl.wrap_socket(sock, cert_reqs = ssl.CERT_REQUIRED, ca_certs = ca_bundle)
42 ssl_match_hostname.match_hostname(sock.getpeercert(), self.host)
43 self.sock = sock
44
47 return self.do_open(self.getConnection, req)
48
50 """@type host: str"""
51 return ValidatingHTTPSConnection(host)
52 MyHTTPSHandler = ValidatingHTTPSHandler
53 break
54 else:
55 raise Exception("No root CA's found (not even the built-in one!); security of HTTPS connections cannot be verified")
56
59 Exception.__init__(self, "Redirect")
60 self.req = req
61
63 """Throw an exception on redirects instead of continuing. The redirect will be handled in the main thread
64 so it can work with connection pooling."""
66 """@type code: int
67 @type msg: str
68 @type newurl: str"""
69 new_req = urllib2.HTTPRedirectHandler.redirect_request(self, req, fp, code, msg, headers, newurl)
70 if new_req:
71 raise Redirect(new_req)
72
73
74
75
76 _my_urlopen = urllib2.OpenerDirector()
77 for klass in [urllib2.ProxyHandler, urllib2.UnknownHandler, urllib2.HTTPHandler,
78 urllib2.HTTPDefaultErrorHandler, MyRedirectHandler,
79 urllib2.FTPHandler, urllib2.HTTPErrorProcessor, MyHTTPSHandler]:
80 _my_urlopen.add_handler(klass())
81
83 """@type url: str
84 @type target_file: file"""
85 src = None
86 try:
87
88 if url.startswith('http:') or url.startswith('https:') or url.startswith('ftp:'):
89 req = urllib2.Request(url)
90 if url.startswith('http:') and if_modified_since:
91 req.add_header('If-Modified-Since', if_modified_since)
92 src = _my_urlopen.open(req)
93 else:
94 raise Exception(_('Unsupported URL protocol in: %s') % url)
95
96 if sys.version_info[0] > 2:
97 sock_recv = src.fp.read1
98 else:
99 try:
100 sock_recv = src.fp._sock.recv
101 except AttributeError:
102 sock_recv = src.fp.fp._sock.recv
103 while True:
104 data = sock_recv(256)
105 if not data: break
106 target_file.write(data)
107 target_file.flush()
108
109 notify_done(download.RESULT_OK)
110 except (urllib2.HTTPError, urllib2.URLError, HTTPException, socket.error) as ex:
111 if isinstance(ex, urllib2.HTTPError) and ex.code == 304:
112 notify_done(download.RESULT_NOT_MODIFIED)
113 else:
114
115 __, ex, tb = sys.exc_info()
116 notify_done(download.RESULT_FAILED, (download.DownloadError(_('Error downloading {url}: {ex}').format(url = url, ex = ex)), tb))
117 except Redirect as ex:
118 notify_done(download.RESULT_REDIRECT, redirect = ex.req.get_full_url())
119 except Exception as ex:
120 __, ex, tb = sys.exc_info()
121 notify_done(download.RESULT_FAILED, (ex, tb))
122 finally:
123 if src is not None:
124 src.close()
125