Mercurial > hg > mercurial-crew
comparison mercurial/httprepo.py @ 2337:3f24bc5dee81
http: fix many problems with url parsing and auth. added proxy test.
problems fixed:
- https scheme handled properly for real and proxy urls.
- url of form "http://user:password@host:port/path" now ok.
- no-proxy check uses proper host names.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Mon, 22 May 2006 15:42:49 -0700 |
parents | f77edcffb837 |
children | ff2bac730b99 |
comparison
equal
deleted
inserted
replaced
2336:f77edcffb837 | 2337:3f24bc5dee81 |
---|---|
20 authinfo = urllib2.HTTPPasswordMgr.find_user_password( | 20 authinfo = urllib2.HTTPPasswordMgr.find_user_password( |
21 self, realm, authuri) | 21 self, realm, authuri) |
22 if authinfo != (None, None): | 22 if authinfo != (None, None): |
23 return authinfo | 23 return authinfo |
24 | 24 |
25 if not ui.interactive: | |
26 raise util.Abort(_('http authorization required')) | |
27 | |
25 self.ui.write(_("http authorization required\n")) | 28 self.ui.write(_("http authorization required\n")) |
26 self.ui.status(_("realm: %s\n") % realm) | 29 self.ui.status(_("realm: %s\n") % realm) |
27 user = self.ui.prompt(_("user:"), default=None) | 30 user = self.ui.prompt(_("user:"), default=None) |
28 passwd = self.ui.getpass() | 31 passwd = self.ui.getpass() |
29 | 32 |
30 self.add_password(realm, authuri, user, passwd) | 33 self.add_password(realm, authuri, user, passwd) |
31 return (user, passwd) | 34 return (user, passwd) |
32 | 35 |
36 def netlocsplit(netloc): | |
37 '''split [user[:passwd]@]host[:port] into 4-tuple.''' | |
38 | |
39 a = netloc.find('@') | |
40 if a == -1: | |
41 user, passwd = None, None | |
42 else: | |
43 userpass, netloc = netloc[:a], netloc[a+1:] | |
44 c = userpass.find(':') | |
45 if c == -1: | |
46 user, passwd = urllib.unquote(userpass), None | |
47 else: | |
48 user = urllib.unquote(userpass[:c]) | |
49 passwd = urllib.unquote(userpass[c+1:]) | |
50 c = netloc.find(':') | |
51 if c == -1: | |
52 host, port = netloc, None | |
53 else: | |
54 host, port = netloc[:c], netloc[c+1:] | |
55 return host, port, user, passwd | |
56 | |
57 def netlocunsplit(host, port, user=None, passwd=None): | |
58 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].''' | |
59 if port: | |
60 hostport = host + ':' + port | |
61 else: | |
62 hostport = host | |
63 if user: | |
64 if passwd: | |
65 userpass = urllib.quote(user) + ':' + urllib.quote(passwd) | |
66 else: | |
67 userpass = urllib.quote(user) | |
68 return userpass + '@' + hostport | |
69 return hostport | |
70 | |
33 class httprepository(remoterepository): | 71 class httprepository(remoterepository): |
34 def __init__(self, ui, path): | 72 def __init__(self, ui, path): |
35 # fix missing / after hostname | 73 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) |
36 s = urlparse.urlsplit(path) | 74 if query or frag: |
37 partial = s[2] | 75 raise util.Abort(_('unsupported URL component: "%s"') % |
38 if not partial: partial = "/" | 76 (query or frag)) |
39 self.url = urlparse.urlunsplit((s[0], s[1], partial, '', '')) | 77 if not urlpath: urlpath = '/' |
78 host, port, user, passwd = netlocsplit(netloc) | |
79 | |
80 # urllib cannot handle URLs with embedded user or passwd | |
81 self.url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), | |
82 urlpath, '', '')) | |
40 self.ui = ui | 83 self.ui = ui |
41 no_list = [ "localhost", "127.0.0.1" ] | 84 |
42 host = ui.config("http_proxy", "host") | 85 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') |
43 if host is None: | 86 proxyauthinfo = None |
44 host = os.environ.get("http_proxy") | 87 handler = urllib2.BaseHandler() |
45 if host and host.startswith('http://'): | 88 |
46 host = host[7:] | 89 if proxyurl: |
47 user = ui.config("http_proxy", "user") | 90 # proxy can be proper url or host[:port] |
48 passwd = ui.config("http_proxy", "passwd") | 91 if not (proxyurl.startswith('http:') or |
49 no = ui.config("http_proxy", "no") | 92 proxyurl.startswith('https:')): |
50 if no is None: | 93 proxyurl = 'http://' + proxyurl + '/' |
51 no = os.environ.get("no_proxy") | 94 snpqf = urlparse.urlsplit(proxyurl) |
52 if no: | 95 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf |
53 no_list = no_list + no.split(",") | 96 hpup = netlocsplit(proxynetloc) |
54 | 97 |
55 no_proxy = 0 | 98 proxyhost, proxyport, proxyuser, proxypasswd = hpup |
56 for h in no_list: | 99 if not proxyuser: |
57 if (path.startswith("http://" + h + "/") or | 100 proxyuser = ui.config("http_proxy", "user") |
58 path.startswith("http://" + h + ":") or | 101 proxypasswd = ui.config("http_proxy", "passwd") |
59 path == "http://" + h): | 102 |
60 no_proxy = 1 | 103 # see if we should use a proxy for this url |
61 | 104 no_list = [ "localhost", "127.0.0.1" ] |
62 # Note: urllib2 takes proxy values from the environment and those will | 105 no_list.extend([p.strip().lower() for |
63 # take precedence | 106 p in ui.config("http_proxy", "no", '').split(',') |
107 if p.strip()]) | |
108 no_list.extend([p.strip().lower() for | |
109 p in os.getenv("no_proxy", '').split(',') | |
110 if p.strip()]) | |
111 # "http_proxy.always" config is for running tests on localhost | |
112 if (not ui.configbool("http_proxy", "always") and | |
113 host.lower() in no_list): | |
114 ui.debug(_('disabling proxy for %s\n') % host) | |
115 else: | |
116 proxyurl = urlparse.urlunsplit(( | |
117 proxyscheme, netlocunsplit(proxyhost, proxyport, | |
118 proxyuser, proxypasswd or ''), | |
119 proxypath, proxyquery, proxyfrag)) | |
120 handler = urllib2.ProxyHandler({scheme: proxyurl}) | |
121 ui.debug(_('proxying through %s\n') % proxyurl) | |
122 | |
123 # urllib2 takes proxy values from the environment and those | |
124 # will take precedence if found, so drop them | |
64 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]: | 125 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]: |
65 try: | 126 try: |
66 if os.environ.has_key(env): | 127 if os.environ.has_key(env): |
67 del os.environ[env] | 128 del os.environ[env] |
68 except OSError: | 129 except OSError: |
69 pass | 130 pass |
70 | 131 |
71 proxy_handler = urllib2.BaseHandler() | 132 passmgr = passwordmgr(ui) |
72 if host and not no_proxy: | 133 if user: |
73 proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host}) | 134 ui.debug(_('will use user %s for http auth\n') % user) |
74 | 135 passmgr.add_password(None, host, user, passwd or '') |
75 proxyauthinfo = None | 136 |
76 if user and passwd: | 137 opener = urllib2.build_opener( |
77 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() | 138 handler, |
78 passmgr.add_password(None, host, user, passwd) | 139 urllib2.HTTPBasicAuthHandler(passmgr), |
79 proxyauthinfo = urllib2.ProxyBasicAuthHandler(passmgr) | 140 urllib2.HTTPDigestAuthHandler(passmgr)) |
80 | |
81 if ui.interactive: | |
82 passmgr = passwordmgr(ui) | |
83 opener = urllib2.build_opener( | |
84 proxy_handler, proxyauthinfo, | |
85 urllib2.HTTPBasicAuthHandler(passmgr), | |
86 urllib2.HTTPDigestAuthHandler(passmgr)) | |
87 else: | |
88 opener = urllib2.build_opener(proxy_handler, proxyauthinfo) | |
89 | 141 |
90 # 1.0 here is the _protocol_ version | 142 # 1.0 here is the _protocol_ version |
91 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] | 143 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] |
92 urllib2.install_opener(opener) | 144 urllib2.install_opener(opener) |
93 | 145 |