##// END OF EJS Templates
factor out the url handling from httprepo...
Benoit Boissinot -
r7270:2db33c1a default
parent child Browse files
Show More
@@ -0,0 +1,302 b''
1 # url.py - HTTP handling for mercurial
2 #
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
9
10 import urllib, urllib2, urlparse, httplib, os, re
11 from i18n import _
12 import keepalive, util
13
14 def hidepassword(url):
15 '''hide user credential in a url string'''
16 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
17 netloc = re.sub('([^:]*):([^@]*)@(.*)', r'\1:***@\3', netloc)
18 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
19
20 def removeauth(url):
21 '''remove all authentication information from a url string'''
22 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
23 netloc = netloc[netloc.find('@')+1:]
24 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
25
26 def netlocsplit(netloc):
27 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
28
29 a = netloc.find('@')
30 if a == -1:
31 user, passwd = None, None
32 else:
33 userpass, netloc = netloc[:a], netloc[a+1:]
34 c = userpass.find(':')
35 if c == -1:
36 user, passwd = urllib.unquote(userpass), None
37 else:
38 user = urllib.unquote(userpass[:c])
39 passwd = urllib.unquote(userpass[c+1:])
40 c = netloc.find(':')
41 if c == -1:
42 host, port = netloc, None
43 else:
44 host, port = netloc[:c], netloc[c+1:]
45 return host, port, user, passwd
46
47 def netlocunsplit(host, port, user=None, passwd=None):
48 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
49 if port:
50 hostport = host + ':' + port
51 else:
52 hostport = host
53 if user:
54 if passwd:
55 userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
56 else:
57 userpass = urllib.quote(user)
58 return userpass + '@' + hostport
59 return hostport
60
61 _safe = ('abcdefghijklmnopqrstuvwxyz'
62 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
63 '0123456789' '_.-/')
64 _safeset = None
65 _hex = None
66 def quotepath(path):
67 '''quote the path part of a URL
68
69 This is similar to urllib.quote, but it also tries to avoid
70 quoting things twice (inspired by wget):
71
72 >>> quotepath('abc def')
73 'abc%20def'
74 >>> quotepath('abc%20def')
75 'abc%20def'
76 >>> quotepath('abc%20 def')
77 'abc%20%20def'
78 >>> quotepath('abc def%20')
79 'abc%20def%20'
80 >>> quotepath('abc def%2')
81 'abc%20def%252'
82 >>> quotepath('abc def%')
83 'abc%20def%25'
84 '''
85 global _safeset, _hex
86 if _safeset is None:
87 _safeset = util.set(_safe)
88 _hex = util.set('abcdefABCDEF0123456789')
89 l = list(path)
90 for i in xrange(len(l)):
91 c = l[i]
92 if c == '%' and i + 2 < len(l) and (l[i+1] in _hex and l[i+2] in _hex):
93 pass
94 elif c not in _safeset:
95 l[i] = '%%%02X' % ord(c)
96 return ''.join(l)
97
98 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
99 def __init__(self, ui):
100 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
101 self.ui = ui
102
103 def find_user_password(self, realm, authuri):
104 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
105 self, realm, authuri)
106 user, passwd = authinfo
107 if user and passwd:
108 return (user, passwd)
109
110 if not self.ui.interactive:
111 raise util.Abort(_('http authorization required'))
112
113 self.ui.write(_("http authorization required\n"))
114 self.ui.status(_("realm: %s\n") % realm)
115 if user:
116 self.ui.status(_("user: %s\n") % user)
117 else:
118 user = self.ui.prompt(_("user:"), default=None)
119
120 if not passwd:
121 passwd = self.ui.getpass()
122
123 self.add_password(realm, authuri, user, passwd)
124 return (user, passwd)
125
126 class proxyhandler(urllib2.ProxyHandler):
127 def __init__(self, ui):
128 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
129 # XXX proxyauthinfo = None
130
131 if proxyurl:
132 # proxy can be proper url or host[:port]
133 if not (proxyurl.startswith('http:') or
134 proxyurl.startswith('https:')):
135 proxyurl = 'http://' + proxyurl + '/'
136 snpqf = urlparse.urlsplit(proxyurl)
137 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
138 hpup = netlocsplit(proxynetloc)
139
140 proxyhost, proxyport, proxyuser, proxypasswd = hpup
141 if not proxyuser:
142 proxyuser = ui.config("http_proxy", "user")
143 proxypasswd = ui.config("http_proxy", "passwd")
144
145 # see if we should use a proxy for this url
146 no_list = [ "localhost", "127.0.0.1" ]
147 no_list.extend([p.lower() for
148 p in ui.configlist("http_proxy", "no")])
149 no_list.extend([p.strip().lower() for
150 p in os.getenv("no_proxy", '').split(',')
151 if p.strip()])
152 # "http_proxy.always" config is for running tests on localhost
153 if ui.configbool("http_proxy", "always"):
154 self.no_list = []
155 else:
156 self.no_list = no_list
157
158 proxyurl = urlparse.urlunsplit((
159 proxyscheme, netlocunsplit(proxyhost, proxyport,
160 proxyuser, proxypasswd or ''),
161 proxypath, proxyquery, proxyfrag))
162 proxies = {'http': proxyurl, 'https': proxyurl}
163 ui.debug(_('proxying through http://%s:%s\n') %
164 (proxyhost, proxyport))
165 else:
166 proxies = {}
167
168 # urllib2 takes proxy values from the environment and those
169 # will take precedence if found, so drop them
170 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
171 try:
172 if env in os.environ:
173 del os.environ[env]
174 except OSError:
175 pass
176
177 urllib2.ProxyHandler.__init__(self, proxies)
178 self.ui = ui
179
180 def proxy_open(self, req, proxy, type_):
181 host = req.get_host().split(':')[0]
182 if host in self.no_list:
183 return None
184
185 # work around a bug in Python < 2.4.2
186 # (it leaves a "\n" at the end of Proxy-authorization headers)
187 baseclass = req.__class__
188 class _request(baseclass):
189 def add_header(self, key, val):
190 if key.lower() == 'proxy-authorization':
191 val = val.strip()
192 return baseclass.add_header(self, key, val)
193 req.__class__ = _request
194
195 return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
196
197 class httpsendfile(file):
198 def __len__(self):
199 return os.fstat(self.fileno()).st_size
200
201 def _gen_sendfile(connection):
202 def _sendfile(self, data):
203 # send a file
204 if isinstance(data, httpsendfile):
205 # if auth required, some data sent twice, so rewind here
206 data.seek(0)
207 for chunk in util.filechunkiter(data):
208 connection.send(self, chunk)
209 else:
210 connection.send(self, data)
211 return _sendfile
212
213 class httpconnection(keepalive.HTTPConnection):
214 # must be able to send big bundle as stream.
215 send = _gen_sendfile(keepalive.HTTPConnection)
216
217 class httphandler(keepalive.HTTPHandler):
218 def http_open(self, req):
219 return self.do_open(httpconnection, req)
220
221 def __del__(self):
222 self.close_all()
223
224 has_https = hasattr(urllib2, 'HTTPSHandler')
225 if has_https:
226 class httpsconnection(httplib.HTTPSConnection):
227 response_class = keepalive.HTTPResponse
228 # must be able to send big bundle as stream.
229 send = _gen_sendfile(httplib.HTTPSConnection)
230
231 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
232 def https_open(self, req):
233 return self.do_open(httpsconnection, req)
234
235 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
236 # it doesn't know about the auth type requested. This can happen if
237 # somebody is using BasicAuth and types a bad password.
238 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
239 def http_error_auth_reqed(self, auth_header, host, req, headers):
240 try:
241 return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
242 self, auth_header, host, req, headers)
243 except ValueError, inst:
244 arg = inst.args[0]
245 if arg.startswith("AbstractDigestAuthHandler doesn't know "):
246 return
247 raise
248
249 def getauthinfo(path):
250 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
251 if not urlpath:
252 urlpath = '/'
253 urlpath = quotepath(urlpath)
254 host, port, user, passwd = netlocsplit(netloc)
255
256 # urllib cannot handle URLs with embedded user or passwd
257 url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
258 urlpath, query, frag))
259 if user:
260 netloc = host
261 if port:
262 netloc += ':' + port
263 # Python < 2.4.3 uses only the netloc to search for a password
264 authinfo = (None, (url, netloc), user, passwd or '')
265 else:
266 authinfo = None
267 return url, authinfo
268
269 def opener(ui, authinfo=None):
270 '''
271 construct an opener suitable for urllib2
272 authinfo will be added to the password manager
273 '''
274 handlers = [httphandler()]
275 if has_https:
276 handlers.append(httpshandler())
277
278 handlers.append(proxyhandler(ui))
279
280 passmgr = passwordmgr(ui)
281 if authinfo is not None:
282 passmgr.add_password(*authinfo)
283 user, passwd = authinfo[2:4]
284 ui.debug(_('http auth: user %s, password %s\n') %
285 (user, passwd and '*' * len(passwd) or 'not set'))
286
287 handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
288 httpdigestauthhandler(passmgr)))
289 opener = urllib2.build_opener(*handlers)
290
291 # 1.0 here is the _protocol_ version
292 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
293 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
294 return opener
295
296 def open(ui, url, data=None):
297 scheme = urlparse.urlsplit(url)[0]
298 if not scheme:
299 url, authinfo = 'file://' + util.normpath(os.path.abspath(url)), None
300 else:
301 url, authinfo = getauthinfo(url)
302 return opener(ui, authinfo).open(url, data)
@@ -8,7 +8,7 b''
8
8
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial.node import nullid, short
10 from mercurial.node import nullid, short
11 from mercurial import commands, cmdutil, hg, util
11 from mercurial import commands, cmdutil, hg, util, url
12
12
13 def fetch(ui, repo, source='default', **opts):
13 def fetch(ui, repo, source='default', **opts):
14 '''Pull changes from a remote repository, merge new changes if needed.
14 '''Pull changes from a remote repository, merge new changes if needed.
@@ -60,7 +60,7 b" def fetch(ui, repo, source='default', **"
60
60
61 other = hg.repository(ui, ui.expandpath(source))
61 other = hg.repository(ui, ui.expandpath(source))
62 ui.status(_('pulling from %s\n') %
62 ui.status(_('pulling from %s\n') %
63 util.hidepassword(ui.expandpath(source)))
63 url.hidepassword(ui.expandpath(source)))
64 revs = None
64 revs = None
65 if opts['rev']:
65 if opts['rev']:
66 if not other.local():
66 if not other.local():
@@ -118,7 +118,7 b" def fetch(ui, repo, source='default', **"
118 mod, add, rem = repo.status()[:3]
118 mod, add, rem = repo.status()[:3]
119 message = (cmdutil.logmessage(opts) or
119 message = (cmdutil.logmessage(opts) or
120 (_('Automated merge with %s') %
120 (_('Automated merge with %s') %
121 util.removeauth(other.url())))
121 url.removeauth(other.url())))
122 force_editor = opts.get('force_editor') or opts.get('edit')
122 force_editor = opts.get('force_editor') or opts.get('edit')
123 n = repo.commit(mod + add + rem, message,
123 n = repo.commit(mod + add + rem, message,
124 opts['user'], opts['date'], force=True,
124 opts['user'], opts['date'], force=True,
@@ -10,7 +10,7 b' from repo import RepoError, NoCapability'
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, urllib
11 import os, re, sys, urllib
12 import hg, util, revlog, bundlerepo, extensions, copies
12 import hg, util, revlog, bundlerepo, extensions, copies
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile, url
14 import version, socket
14 import version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
16 import merge as merge_
16 import merge as merge_
@@ -1675,7 +1675,7 b' def incoming(ui, repo, source="default",'
1675 cmdutil.setremoteconfig(ui, opts)
1675 cmdutil.setremoteconfig(ui, opts)
1676
1676
1677 other = hg.repository(ui, source)
1677 other = hg.repository(ui, source)
1678 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1678 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1679 if revs:
1679 if revs:
1680 revs = [other.lookup(rev) for rev in revs]
1680 revs = [other.lookup(rev) for rev in revs]
1681 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1681 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
@@ -1997,7 +1997,7 b' def outgoing(ui, repo, dest=None, **opts'
1997 revs = [repo.lookup(rev) for rev in revs]
1997 revs = [repo.lookup(rev) for rev in revs]
1998
1998
1999 other = hg.repository(ui, dest)
1999 other = hg.repository(ui, dest)
2000 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2000 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2001 o = repo.findoutgoing(other, force=opts.get('force'))
2001 o = repo.findoutgoing(other, force=opts.get('force'))
2002 if not o:
2002 if not o:
2003 ui.status(_("no changes found\n"))
2003 ui.status(_("no changes found\n"))
@@ -2068,13 +2068,13 b' def paths(ui, repo, search=None):'
2068 if search:
2068 if search:
2069 for name, path in ui.configitems("paths"):
2069 for name, path in ui.configitems("paths"):
2070 if name == search:
2070 if name == search:
2071 ui.write("%s\n" % util.hidepassword(path))
2071 ui.write("%s\n" % url.hidepassword(path))
2072 return
2072 return
2073 ui.warn(_("not found!\n"))
2073 ui.warn(_("not found!\n"))
2074 return 1
2074 return 1
2075 else:
2075 else:
2076 for name, path in ui.configitems("paths"):
2076 for name, path in ui.configitems("paths"):
2077 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2077 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2078
2078
2079 def postincoming(ui, repo, modheads, optupdate, checkout):
2079 def postincoming(ui, repo, modheads, optupdate, checkout):
2080 if modheads == 0:
2080 if modheads == 0:
@@ -2131,7 +2131,7 b' def pull(ui, repo, source="default", **o'
2131 cmdutil.setremoteconfig(ui, opts)
2131 cmdutil.setremoteconfig(ui, opts)
2132
2132
2133 other = hg.repository(ui, source)
2133 other = hg.repository(ui, source)
2134 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2134 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2135 if revs:
2135 if revs:
2136 try:
2136 try:
2137 revs = [other.lookup(rev) for rev in revs]
2137 revs = [other.lookup(rev) for rev in revs]
@@ -2179,7 +2179,7 b' def push(ui, repo, dest=None, **opts):'
2179 cmdutil.setremoteconfig(ui, opts)
2179 cmdutil.setremoteconfig(ui, opts)
2180
2180
2181 other = hg.repository(ui, dest)
2181 other = hg.repository(ui, dest)
2182 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
2182 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2183 if revs:
2183 if revs:
2184 revs = [repo.lookup(rev) for rev in revs]
2184 revs = [repo.lookup(rev) for rev in revs]
2185 r = repo.push(other, opts.get('force'), revs=revs)
2185 r = repo.push(other, opts.get('force'), revs=revs)
@@ -10,189 +10,7 b' from node import bin, hex, nullid'
10 from i18n import _
10 from i18n import _
11 import repo, os, urllib, urllib2, urlparse, zlib, util, httplib
11 import repo, os, urllib, urllib2, urlparse, zlib, util, httplib
12 import errno, keepalive, socket, changegroup, statichttprepo
12 import errno, keepalive, socket, changegroup, statichttprepo
13
13 import url
14 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
15 def __init__(self, ui):
16 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
17 self.ui = ui
18
19 def find_user_password(self, realm, authuri):
20 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
21 self, realm, authuri)
22 user, passwd = authinfo
23 if user and passwd:
24 return (user, passwd)
25
26 if not self.ui.interactive:
27 raise util.Abort(_('http authorization required'))
28
29 self.ui.write(_("http authorization required\n"))
30 self.ui.status(_("realm: %s\n") % realm)
31 if user:
32 self.ui.status(_("user: %s\n") % user)
33 else:
34 user = self.ui.prompt(_("user:"), default=None)
35
36 if not passwd:
37 passwd = self.ui.getpass()
38
39 self.add_password(realm, authuri, user, passwd)
40 return (user, passwd)
41
42 class proxyhandler(urllib2.ProxyHandler):
43 def __init__(self, ui):
44 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
45 # XXX proxyauthinfo = None
46
47 if proxyurl:
48 # proxy can be proper url or host[:port]
49 if not (proxyurl.startswith('http:') or
50 proxyurl.startswith('https:')):
51 proxyurl = 'http://' + proxyurl + '/'
52 snpqf = urlparse.urlsplit(proxyurl)
53 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
54 hpup = netlocsplit(proxynetloc)
55
56 proxyhost, proxyport, proxyuser, proxypasswd = hpup
57 if not proxyuser:
58 proxyuser = ui.config("http_proxy", "user")
59 proxypasswd = ui.config("http_proxy", "passwd")
60
61 # see if we should use a proxy for this url
62 no_list = [ "localhost", "127.0.0.1" ]
63 no_list.extend([p.lower() for
64 p in ui.configlist("http_proxy", "no")])
65 no_list.extend([p.strip().lower() for
66 p in os.getenv("no_proxy", '').split(',')
67 if p.strip()])
68 # "http_proxy.always" config is for running tests on localhost
69 if ui.configbool("http_proxy", "always"):
70 self.no_list = []
71 else:
72 self.no_list = no_list
73
74 proxyurl = urlparse.urlunsplit((
75 proxyscheme, netlocunsplit(proxyhost, proxyport,
76 proxyuser, proxypasswd or ''),
77 proxypath, proxyquery, proxyfrag))
78 proxies = {'http': proxyurl, 'https': proxyurl}
79 ui.debug(_('proxying through http://%s:%s\n') %
80 (proxyhost, proxyport))
81 else:
82 proxies = {}
83
84 # urllib2 takes proxy values from the environment and those
85 # will take precedence if found, so drop them
86 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
87 try:
88 if env in os.environ:
89 del os.environ[env]
90 except OSError:
91 pass
92
93 urllib2.ProxyHandler.__init__(self, proxies)
94 self.ui = ui
95
96 def proxy_open(self, req, proxy, type):
97 host = req.get_host().split(':')[0]
98 if host in self.no_list:
99 return None
100 return urllib2.ProxyHandler.proxy_open(self, req, proxy, type)
101
102 def netlocsplit(netloc):
103 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
104
105 a = netloc.find('@')
106 if a == -1:
107 user, passwd = None, None
108 else:
109 userpass, netloc = netloc[:a], netloc[a+1:]
110 c = userpass.find(':')
111 if c == -1:
112 user, passwd = urllib.unquote(userpass), None
113 else:
114 user = urllib.unquote(userpass[:c])
115 passwd = urllib.unquote(userpass[c+1:])
116 c = netloc.find(':')
117 if c == -1:
118 host, port = netloc, None
119 else:
120 host, port = netloc[:c], netloc[c+1:]
121 return host, port, user, passwd
122
123 def netlocunsplit(host, port, user=None, passwd=None):
124 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
125 if port:
126 hostport = host + ':' + port
127 else:
128 hostport = host
129 if user:
130 if passwd:
131 userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
132 else:
133 userpass = urllib.quote(user)
134 return userpass + '@' + hostport
135 return hostport
136
137 # work around a bug in Python < 2.4.2
138 # (it leaves a "\n" at the end of Proxy-authorization headers)
139 class request(urllib2.Request):
140 def add_header(self, key, val):
141 if key.lower() == 'proxy-authorization':
142 val = val.strip()
143 return urllib2.Request.add_header(self, key, val)
144
145 class httpsendfile(file):
146 def __len__(self):
147 return os.fstat(self.fileno()).st_size
148
149 def _gen_sendfile(connection):
150 def _sendfile(self, data):
151 # send a file
152 if isinstance(data, httpsendfile):
153 # if auth required, some data sent twice, so rewind here
154 data.seek(0)
155 for chunk in util.filechunkiter(data):
156 connection.send(self, chunk)
157 else:
158 connection.send(self, data)
159 return _sendfile
160
161 class httpconnection(keepalive.HTTPConnection):
162 # must be able to send big bundle as stream.
163 send = _gen_sendfile(keepalive.HTTPConnection)
164
165 class httphandler(keepalive.HTTPHandler):
166 def http_open(self, req):
167 return self.do_open(httpconnection, req)
168
169 def __del__(self):
170 self.close_all()
171
172 has_https = hasattr(urllib2, 'HTTPSHandler')
173 if has_https:
174 class httpsconnection(httplib.HTTPSConnection):
175 response_class = keepalive.HTTPResponse
176 # must be able to send big bundle as stream.
177 send = _gen_sendfile(httplib.HTTPSConnection)
178
179 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
180 def https_open(self, req):
181 return self.do_open(httpsconnection, req)
182
183 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
184 # it doesn't know about the auth type requested. This can happen if
185 # somebody is using BasicAuth and types a bad password.
186 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
187 def http_error_auth_reqed(self, auth_header, host, req, headers):
188 try:
189 return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
190 self, auth_header, host, req, headers)
191 except ValueError, inst:
192 arg = inst.args[0]
193 if arg.startswith("AbstractDigestAuthHandler doesn't know "):
194 return
195 raise
196
14
197 def zgenerator(f):
15 def zgenerator(f):
198 zd = zlib.decompressobj()
16 zd = zlib.decompressobj()
@@ -203,43 +21,6 b' def zgenerator(f):'
203 raise IOError(None, _('connection ended unexpectedly'))
21 raise IOError(None, _('connection ended unexpectedly'))
204 yield zd.flush()
22 yield zd.flush()
205
23
206 _safe = ('abcdefghijklmnopqrstuvwxyz'
207 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
208 '0123456789' '_.-/')
209 _safeset = None
210 _hex = None
211 def quotepath(path):
212 '''quote the path part of a URL
213
214 This is similar to urllib.quote, but it also tries to avoid
215 quoting things twice (inspired by wget):
216
217 >>> quotepath('abc def')
218 'abc%20def'
219 >>> quotepath('abc%20def')
220 'abc%20def'
221 >>> quotepath('abc%20 def')
222 'abc%20%20def'
223 >>> quotepath('abc def%20')
224 'abc%20def%20'
225 >>> quotepath('abc def%2')
226 'abc%20def%252'
227 >>> quotepath('abc def%')
228 'abc%20def%25'
229 '''
230 global _safeset, _hex
231 if _safeset is None:
232 _safeset = util.set(_safe)
233 _hex = util.set('abcdefABCDEF0123456789')
234 l = list(path)
235 for i in xrange(len(l)):
236 c = l[i]
237 if c == '%' and i + 2 < len(l) and (l[i+1] in _hex and l[i+2] in _hex):
238 pass
239 elif c not in _safeset:
240 l[i] = '%%%02X' % ord(c)
241 return ''.join(l)
242
243 class httprepository(repo.repository):
24 class httprepository(repo.repository):
244 def __init__(self, ui, path):
25 def __init__(self, ui, path):
245 self.path = path
26 self.path = path
@@ -249,41 +30,14 b' class httprepository(repo.repository):'
249 if query or frag:
30 if query or frag:
250 raise util.Abort(_('unsupported URL component: "%s"') %
31 raise util.Abort(_('unsupported URL component: "%s"') %
251 (query or frag))
32 (query or frag))
252 if not urlpath:
253 urlpath = '/'
254 urlpath = quotepath(urlpath)
255 host, port, user, passwd = netlocsplit(netloc)
256
33
257 # urllib cannot handle URLs with embedded user or passwd
34 # urllib cannot handle URLs with embedded user or passwd
258 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
35 self._url, authinfo = url.getauthinfo(path)
259 urlpath, '', ''))
36
260 self.ui = ui
37 self.ui = ui
261 self.ui.debug(_('using %s\n') % self._url)
38 self.ui.debug(_('using %s\n') % self._url)
262
39
263 handlers = [httphandler()]
40 self.urlopener = url.opener(ui, authinfo)
264 if has_https:
265 handlers.append(httpshandler())
266
267 handlers.append(proxyhandler(ui))
268
269 passmgr = passwordmgr(ui)
270 if user:
271 ui.debug(_('http auth: user %s, password %s\n') %
272 (user, passwd and '*' * len(passwd) or 'not set'))
273 netloc = host
274 if port:
275 netloc += ':' + port
276 # Python < 2.4.3 uses only the netloc to search for a password
277 passmgr.add_password(None, (self._url, netloc), user, passwd or '')
278
279 handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
280 httpdigestauthhandler(passmgr)))
281 opener = urllib2.build_opener(*handlers)
282
283 # 1.0 here is the _protocol_ version
284 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
285 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
286 urllib2.install_opener(opener)
287
41
288 def url(self):
42 def url(self):
289 return self.path
43 return self.path
@@ -316,7 +70,7 b' class httprepository(repo.repository):'
316 try:
70 try:
317 if data:
71 if data:
318 self.ui.debug(_("sending %s bytes\n") % len(data))
72 self.ui.debug(_("sending %s bytes\n") % len(data))
319 resp = urllib2.urlopen(request(cu, data, headers))
73 resp = self.urlopener.open(urllib2.Request(cu, data, headers))
320 except urllib2.HTTPError, inst:
74 except urllib2.HTTPError, inst:
321 if inst.code == 401:
75 if inst.code == 401:
322 raise util.Abort(_('authorization failed'))
76 raise util.Abort(_('authorization failed'))
@@ -433,7 +187,7 b' class httprepository(repo.repository):'
433 break
187 break
434
188
435 tempname = changegroup.writebundle(cg, None, type)
189 tempname = changegroup.writebundle(cg, None, type)
436 fp = httpsendfile(tempname, "rb")
190 fp = url.httpsendfile(tempname, "rb")
437 try:
191 try:
438 try:
192 try:
439 resp = self.do_read(
193 resp = self.do_read(
@@ -15,7 +15,7 b' platform-specific details from the core.'
15 from i18n import _
15 from i18n import _
16 import cStringIO, errno, getpass, re, shutil, sys, tempfile
16 import cStringIO, errno, getpass, re, shutil, sys, tempfile
17 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
17 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
18 import imp, urlparse
18 import imp
19
19
20 # Python compatibility
20 # Python compatibility
21
21
@@ -1932,15 +1932,3 b' def drop_scheme(scheme, path):'
1932 def uirepr(s):
1932 def uirepr(s):
1933 # Avoid double backslash in Windows path repr()
1933 # Avoid double backslash in Windows path repr()
1934 return repr(s).replace('\\\\', '\\')
1934 return repr(s).replace('\\\\', '\\')
1935
1936 def hidepassword(url):
1937 '''hide user credential in a url string'''
1938 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
1939 netloc = re.sub('([^:]*):([^@]*)@(.*)', r'\1:***@\3', netloc)
1940 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
1941
1942 def removeauth(url):
1943 '''remove all authentication information from a url string'''
1944 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
1945 netloc = netloc[netloc.find('@')+1:]
1946 return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
General Comments 0
You need to be logged in to leave comments. Login now