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