##// END OF EJS Templates
do not disclose proxy user and password in debug messages
TK Soh -
r3170:36ab673f default
parent child Browse files
Show More
@@ -1,351 +1,352 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from node import *
9 from node import *
10 from remoterepo import *
10 from remoterepo import *
11 from i18n import gettext as _
11 from i18n import gettext as _
12 from demandload import *
12 from demandload import *
13 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
13 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
14 demandload(globals(), "errno keepalive tempfile socket")
14 demandload(globals(), "errno keepalive tempfile socket")
15
15
16 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
16 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
17 def __init__(self, ui):
17 def __init__(self, ui):
18 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
18 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
19 self.ui = ui
19 self.ui = ui
20
20
21 def find_user_password(self, realm, authuri):
21 def find_user_password(self, realm, authuri):
22 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
22 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
23 self, realm, authuri)
23 self, realm, authuri)
24 user, passwd = authinfo
24 user, passwd = authinfo
25 if user and passwd:
25 if user and passwd:
26 return (user, passwd)
26 return (user, passwd)
27
27
28 if not self.ui.interactive:
28 if not self.ui.interactive:
29 raise util.Abort(_('http authorization required'))
29 raise util.Abort(_('http authorization required'))
30
30
31 self.ui.write(_("http authorization required\n"))
31 self.ui.write(_("http authorization required\n"))
32 self.ui.status(_("realm: %s\n") % realm)
32 self.ui.status(_("realm: %s\n") % realm)
33 if user:
33 if user:
34 self.ui.status(_("user: %s\n") % user)
34 self.ui.status(_("user: %s\n") % user)
35 else:
35 else:
36 user = self.ui.prompt(_("user:"), default=None)
36 user = self.ui.prompt(_("user:"), default=None)
37
37
38 if not passwd:
38 if not passwd:
39 passwd = self.ui.getpass()
39 passwd = self.ui.getpass()
40
40
41 self.add_password(realm, authuri, user, passwd)
41 self.add_password(realm, authuri, user, passwd)
42 return (user, passwd)
42 return (user, passwd)
43
43
44 def netlocsplit(netloc):
44 def netlocsplit(netloc):
45 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
45 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
46
46
47 a = netloc.find('@')
47 a = netloc.find('@')
48 if a == -1:
48 if a == -1:
49 user, passwd = None, None
49 user, passwd = None, None
50 else:
50 else:
51 userpass, netloc = netloc[:a], netloc[a+1:]
51 userpass, netloc = netloc[:a], netloc[a+1:]
52 c = userpass.find(':')
52 c = userpass.find(':')
53 if c == -1:
53 if c == -1:
54 user, passwd = urllib.unquote(userpass), None
54 user, passwd = urllib.unquote(userpass), None
55 else:
55 else:
56 user = urllib.unquote(userpass[:c])
56 user = urllib.unquote(userpass[:c])
57 passwd = urllib.unquote(userpass[c+1:])
57 passwd = urllib.unquote(userpass[c+1:])
58 c = netloc.find(':')
58 c = netloc.find(':')
59 if c == -1:
59 if c == -1:
60 host, port = netloc, None
60 host, port = netloc, None
61 else:
61 else:
62 host, port = netloc[:c], netloc[c+1:]
62 host, port = netloc[:c], netloc[c+1:]
63 return host, port, user, passwd
63 return host, port, user, passwd
64
64
65 def netlocunsplit(host, port, user=None, passwd=None):
65 def netlocunsplit(host, port, user=None, passwd=None):
66 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
66 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
67 if port:
67 if port:
68 hostport = host + ':' + port
68 hostport = host + ':' + port
69 else:
69 else:
70 hostport = host
70 hostport = host
71 if user:
71 if user:
72 if passwd:
72 if passwd:
73 userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
73 userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
74 else:
74 else:
75 userpass = urllib.quote(user)
75 userpass = urllib.quote(user)
76 return userpass + '@' + hostport
76 return userpass + '@' + hostport
77 return hostport
77 return hostport
78
78
79 class httpconnection(keepalive.HTTPConnection):
79 class httpconnection(keepalive.HTTPConnection):
80 # must be able to send big bundle as stream.
80 # must be able to send big bundle as stream.
81
81
82 def send(self, data):
82 def send(self, data):
83 if isinstance(data, str):
83 if isinstance(data, str):
84 keepalive.HTTPConnection.send(self, data)
84 keepalive.HTTPConnection.send(self, data)
85 else:
85 else:
86 # if auth required, some data sent twice, so rewind here
86 # if auth required, some data sent twice, so rewind here
87 data.seek(0)
87 data.seek(0)
88 for chunk in util.filechunkiter(data):
88 for chunk in util.filechunkiter(data):
89 keepalive.HTTPConnection.send(self, chunk)
89 keepalive.HTTPConnection.send(self, chunk)
90
90
91 class basehttphandler(keepalive.HTTPHandler):
91 class basehttphandler(keepalive.HTTPHandler):
92 def http_open(self, req):
92 def http_open(self, req):
93 return self.do_open(httpconnection, req)
93 return self.do_open(httpconnection, req)
94
94
95 has_https = hasattr(urllib2, 'HTTPSHandler')
95 has_https = hasattr(urllib2, 'HTTPSHandler')
96 if has_https:
96 if has_https:
97 class httpsconnection(httplib.HTTPSConnection):
97 class httpsconnection(httplib.HTTPSConnection):
98 response_class = keepalive.HTTPResponse
98 response_class = keepalive.HTTPResponse
99 # must be able to send big bundle as stream.
99 # must be able to send big bundle as stream.
100
100
101 def send(self, data):
101 def send(self, data):
102 if isinstance(data, str):
102 if isinstance(data, str):
103 httplib.HTTPSConnection.send(self, data)
103 httplib.HTTPSConnection.send(self, data)
104 else:
104 else:
105 # if auth required, some data sent twice, so rewind here
105 # if auth required, some data sent twice, so rewind here
106 data.seek(0)
106 data.seek(0)
107 for chunk in util.filechunkiter(data):
107 for chunk in util.filechunkiter(data):
108 httplib.HTTPSConnection.send(self, chunk)
108 httplib.HTTPSConnection.send(self, chunk)
109
109
110 class httphandler(basehttphandler, urllib2.HTTPSHandler):
110 class httphandler(basehttphandler, urllib2.HTTPSHandler):
111 def https_open(self, req):
111 def https_open(self, req):
112 return self.do_open(httpsconnection, req)
112 return self.do_open(httpsconnection, req)
113 else:
113 else:
114 class httphandler(basehttphandler):
114 class httphandler(basehttphandler):
115 pass
115 pass
116
116
117 class httprepository(remoterepository):
117 class httprepository(remoterepository):
118 def __init__(self, ui, path):
118 def __init__(self, ui, path):
119 self.path = path
119 self.path = path
120 self.caps = None
120 self.caps = None
121 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
121 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
122 if query or frag:
122 if query or frag:
123 raise util.Abort(_('unsupported URL component: "%s"') %
123 raise util.Abort(_('unsupported URL component: "%s"') %
124 (query or frag))
124 (query or frag))
125 if not urlpath: urlpath = '/'
125 if not urlpath: urlpath = '/'
126 host, port, user, passwd = netlocsplit(netloc)
126 host, port, user, passwd = netlocsplit(netloc)
127
127
128 # urllib cannot handle URLs with embedded user or passwd
128 # urllib cannot handle URLs with embedded user or passwd
129 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
129 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
130 urlpath, '', ''))
130 urlpath, '', ''))
131 self.ui = ui
131 self.ui = ui
132
132
133 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
133 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
134 # XXX proxyauthinfo = None
134 # XXX proxyauthinfo = None
135 handler = httphandler()
135 handler = httphandler()
136
136
137 if proxyurl:
137 if proxyurl:
138 # proxy can be proper url or host[:port]
138 # proxy can be proper url or host[:port]
139 if not (proxyurl.startswith('http:') or
139 if not (proxyurl.startswith('http:') or
140 proxyurl.startswith('https:')):
140 proxyurl.startswith('https:')):
141 proxyurl = 'http://' + proxyurl + '/'
141 proxyurl = 'http://' + proxyurl + '/'
142 snpqf = urlparse.urlsplit(proxyurl)
142 snpqf = urlparse.urlsplit(proxyurl)
143 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
143 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
144 hpup = netlocsplit(proxynetloc)
144 hpup = netlocsplit(proxynetloc)
145
145
146 proxyhost, proxyport, proxyuser, proxypasswd = hpup
146 proxyhost, proxyport, proxyuser, proxypasswd = hpup
147 if not proxyuser:
147 if not proxyuser:
148 proxyuser = ui.config("http_proxy", "user")
148 proxyuser = ui.config("http_proxy", "user")
149 proxypasswd = ui.config("http_proxy", "passwd")
149 proxypasswd = ui.config("http_proxy", "passwd")
150
150
151 # see if we should use a proxy for this url
151 # see if we should use a proxy for this url
152 no_list = [ "localhost", "127.0.0.1" ]
152 no_list = [ "localhost", "127.0.0.1" ]
153 no_list.extend([p.lower() for
153 no_list.extend([p.lower() for
154 p in ui.configlist("http_proxy", "no")])
154 p in ui.configlist("http_proxy", "no")])
155 no_list.extend([p.strip().lower() for
155 no_list.extend([p.strip().lower() for
156 p in os.getenv("no_proxy", '').split(',')
156 p in os.getenv("no_proxy", '').split(',')
157 if p.strip()])
157 if p.strip()])
158 # "http_proxy.always" config is for running tests on localhost
158 # "http_proxy.always" config is for running tests on localhost
159 if (not ui.configbool("http_proxy", "always") and
159 if (not ui.configbool("http_proxy", "always") and
160 host.lower() in no_list):
160 host.lower() in no_list):
161 ui.debug(_('disabling proxy for %s\n') % host)
161 ui.debug(_('disabling proxy for %s\n') % host)
162 else:
162 else:
163 proxyurl = urlparse.urlunsplit((
163 proxyurl = urlparse.urlunsplit((
164 proxyscheme, netlocunsplit(proxyhost, proxyport,
164 proxyscheme, netlocunsplit(proxyhost, proxyport,
165 proxyuser, proxypasswd or ''),
165 proxyuser, proxypasswd or ''),
166 proxypath, proxyquery, proxyfrag))
166 proxypath, proxyquery, proxyfrag))
167 handler = urllib2.ProxyHandler({scheme: proxyurl})
167 handler = urllib2.ProxyHandler({scheme: proxyurl})
168 ui.debug(_('proxying through %s\n') % proxyurl)
168 ui.debug(_('proxying through http://%s:%s\n') %
169 (proxyhost, proxyport))
169
170
170 # urllib2 takes proxy values from the environment and those
171 # urllib2 takes proxy values from the environment and those
171 # will take precedence if found, so drop them
172 # will take precedence if found, so drop them
172 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
173 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
173 try:
174 try:
174 if os.environ.has_key(env):
175 if os.environ.has_key(env):
175 del os.environ[env]
176 del os.environ[env]
176 except OSError:
177 except OSError:
177 pass
178 pass
178
179
179 passmgr = passwordmgr(ui)
180 passmgr = passwordmgr(ui)
180 if user:
181 if user:
181 ui.debug(_('http auth: user %s, password %s\n') %
182 ui.debug(_('http auth: user %s, password %s\n') %
182 (user, passwd and '*' * len(passwd) or 'not set'))
183 (user, passwd and '*' * len(passwd) or 'not set'))
183 passmgr.add_password(None, host, user, passwd or '')
184 passmgr.add_password(None, host, user, passwd or '')
184
185
185 opener = urllib2.build_opener(
186 opener = urllib2.build_opener(
186 handler,
187 handler,
187 urllib2.HTTPBasicAuthHandler(passmgr),
188 urllib2.HTTPBasicAuthHandler(passmgr),
188 urllib2.HTTPDigestAuthHandler(passmgr))
189 urllib2.HTTPDigestAuthHandler(passmgr))
189
190
190 # 1.0 here is the _protocol_ version
191 # 1.0 here is the _protocol_ version
191 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
192 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
192 urllib2.install_opener(opener)
193 urllib2.install_opener(opener)
193
194
194 def url(self):
195 def url(self):
195 return self.path
196 return self.path
196
197
197 # look up capabilities only when needed
198 # look up capabilities only when needed
198
199
199 def get_caps(self):
200 def get_caps(self):
200 if self.caps is None:
201 if self.caps is None:
201 try:
202 try:
202 self.caps = self.do_read('capabilities').split()
203 self.caps = self.do_read('capabilities').split()
203 except hg.RepoError:
204 except hg.RepoError:
204 self.caps = ()
205 self.caps = ()
205 self.ui.debug(_('capabilities: %s\n') %
206 self.ui.debug(_('capabilities: %s\n') %
206 (' '.join(self.caps or ['none'])))
207 (' '.join(self.caps or ['none'])))
207 return self.caps
208 return self.caps
208
209
209 capabilities = property(get_caps)
210 capabilities = property(get_caps)
210
211
211 def lock(self):
212 def lock(self):
212 raise util.Abort(_('operation not supported over http'))
213 raise util.Abort(_('operation not supported over http'))
213
214
214 def do_cmd(self, cmd, **args):
215 def do_cmd(self, cmd, **args):
215 data = args.pop('data', None)
216 data = args.pop('data', None)
216 headers = args.pop('headers', {})
217 headers = args.pop('headers', {})
217 self.ui.debug(_("sending %s command\n") % cmd)
218 self.ui.debug(_("sending %s command\n") % cmd)
218 q = {"cmd": cmd}
219 q = {"cmd": cmd}
219 q.update(args)
220 q.update(args)
220 qs = urllib.urlencode(q)
221 qs = urllib.urlencode(q)
221 cu = "%s?%s" % (self._url, qs)
222 cu = "%s?%s" % (self._url, qs)
222 try:
223 try:
223 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
224 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
224 except urllib2.HTTPError, inst:
225 except urllib2.HTTPError, inst:
225 if inst.code == 401:
226 if inst.code == 401:
226 raise util.Abort(_('authorization failed'))
227 raise util.Abort(_('authorization failed'))
227 raise
228 raise
228 except httplib.HTTPException, inst:
229 except httplib.HTTPException, inst:
229 self.ui.debug(_('http error while sending %s command\n') % cmd)
230 self.ui.debug(_('http error while sending %s command\n') % cmd)
230 self.ui.print_exc()
231 self.ui.print_exc()
231 raise IOError(None, inst)
232 raise IOError(None, inst)
232 try:
233 try:
233 proto = resp.getheader('content-type')
234 proto = resp.getheader('content-type')
234 except AttributeError:
235 except AttributeError:
235 proto = resp.headers['content-type']
236 proto = resp.headers['content-type']
236
237
237 # accept old "text/plain" and "application/hg-changegroup" for now
238 # accept old "text/plain" and "application/hg-changegroup" for now
238 if not proto.startswith('application/mercurial') and \
239 if not proto.startswith('application/mercurial') and \
239 not proto.startswith('text/plain') and \
240 not proto.startswith('text/plain') and \
240 not proto.startswith('application/hg-changegroup'):
241 not proto.startswith('application/hg-changegroup'):
241 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
242 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
242 self._url)
243 self._url)
243
244
244 if proto.startswith('application/mercurial'):
245 if proto.startswith('application/mercurial'):
245 version = proto[22:]
246 version = proto[22:]
246 if float(version) > 0.1:
247 if float(version) > 0.1:
247 raise hg.RepoError(_("'%s' uses newer protocol %s") %
248 raise hg.RepoError(_("'%s' uses newer protocol %s") %
248 (self._url, version))
249 (self._url, version))
249
250
250 return resp
251 return resp
251
252
252 def do_read(self, cmd, **args):
253 def do_read(self, cmd, **args):
253 fp = self.do_cmd(cmd, **args)
254 fp = self.do_cmd(cmd, **args)
254 try:
255 try:
255 return fp.read()
256 return fp.read()
256 finally:
257 finally:
257 # if using keepalive, allow connection to be reused
258 # if using keepalive, allow connection to be reused
258 fp.close()
259 fp.close()
259
260
260 def heads(self):
261 def heads(self):
261 d = self.do_read("heads")
262 d = self.do_read("heads")
262 try:
263 try:
263 return map(bin, d[:-1].split(" "))
264 return map(bin, d[:-1].split(" "))
264 except:
265 except:
265 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
266 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
266 raise
267 raise
267
268
268 def branches(self, nodes):
269 def branches(self, nodes):
269 n = " ".join(map(hex, nodes))
270 n = " ".join(map(hex, nodes))
270 d = self.do_read("branches", nodes=n)
271 d = self.do_read("branches", nodes=n)
271 try:
272 try:
272 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
273 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
273 return br
274 return br
274 except:
275 except:
275 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
276 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
276 raise
277 raise
277
278
278 def between(self, pairs):
279 def between(self, pairs):
279 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
280 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
280 d = self.do_read("between", pairs=n)
281 d = self.do_read("between", pairs=n)
281 try:
282 try:
282 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
283 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
283 return p
284 return p
284 except:
285 except:
285 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
286 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
286 raise
287 raise
287
288
288 def changegroup(self, nodes, kind):
289 def changegroup(self, nodes, kind):
289 n = " ".join(map(hex, nodes))
290 n = " ".join(map(hex, nodes))
290 f = self.do_cmd("changegroup", roots=n)
291 f = self.do_cmd("changegroup", roots=n)
291
292
292 def zgenerator(f):
293 def zgenerator(f):
293 zd = zlib.decompressobj()
294 zd = zlib.decompressobj()
294 try:
295 try:
295 for chnk in f:
296 for chnk in f:
296 yield zd.decompress(chnk)
297 yield zd.decompress(chnk)
297 except httplib.HTTPException:
298 except httplib.HTTPException:
298 raise IOError(None, _('connection ended unexpectedly'))
299 raise IOError(None, _('connection ended unexpectedly'))
299 yield zd.flush()
300 yield zd.flush()
300
301
301 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
302 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
302
303
303 def unbundle(self, cg, heads, source):
304 def unbundle(self, cg, heads, source):
304 # have to stream bundle to a temp file because we do not have
305 # have to stream bundle to a temp file because we do not have
305 # http 1.1 chunked transfer.
306 # http 1.1 chunked transfer.
306
307
307 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
308 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
308 fp = os.fdopen(fd, 'wb+')
309 fp = os.fdopen(fd, 'wb+')
309 try:
310 try:
310 for chunk in util.filechunkiter(cg):
311 for chunk in util.filechunkiter(cg):
311 fp.write(chunk)
312 fp.write(chunk)
312 length = fp.tell()
313 length = fp.tell()
313 try:
314 try:
314 rfp = self.do_cmd(
315 rfp = self.do_cmd(
315 'unbundle', data=fp,
316 'unbundle', data=fp,
316 headers={'content-length': length,
317 headers={'content-length': length,
317 'content-type': 'application/octet-stream'},
318 'content-type': 'application/octet-stream'},
318 heads=' '.join(map(hex, heads)))
319 heads=' '.join(map(hex, heads)))
319 try:
320 try:
320 ret = int(rfp.readline())
321 ret = int(rfp.readline())
321 self.ui.write(rfp.read())
322 self.ui.write(rfp.read())
322 return ret
323 return ret
323 finally:
324 finally:
324 rfp.close()
325 rfp.close()
325 except socket.error, err:
326 except socket.error, err:
326 if err[0] in (errno.ECONNRESET, errno.EPIPE):
327 if err[0] in (errno.ECONNRESET, errno.EPIPE):
327 raise util.Abort(_('push failed: %s') % err[1])
328 raise util.Abort(_('push failed: %s') % err[1])
328 raise util.Abort(err[1])
329 raise util.Abort(err[1])
329 finally:
330 finally:
330 fp.close()
331 fp.close()
331 os.unlink(tempname)
332 os.unlink(tempname)
332
333
333 def stream_out(self):
334 def stream_out(self):
334 return self.do_cmd('stream_out')
335 return self.do_cmd('stream_out')
335
336
336 class httpsrepository(httprepository):
337 class httpsrepository(httprepository):
337 def __init__(self, ui, path):
338 def __init__(self, ui, path):
338 if not has_https:
339 if not has_https:
339 raise util.Abort(_('Python support for SSL and HTTPS '
340 raise util.Abort(_('Python support for SSL and HTTPS '
340 'is not installed'))
341 'is not installed'))
341 httprepository.__init__(self, ui, path)
342 httprepository.__init__(self, ui, path)
342
343
343 def instance(ui, path, create):
344 def instance(ui, path, create):
344 if create:
345 if create:
345 raise util.Abort(_('cannot create new http repository'))
346 raise util.Abort(_('cannot create new http repository'))
346 if path.startswith('hg:'):
347 if path.startswith('hg:'):
347 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
348 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
348 path = 'http:' + path[3:]
349 path = 'http:' + path[3:]
349 if path.startswith('https:'):
350 if path.startswith('https:'):
350 return httpsrepository(ui, path)
351 return httpsrepository(ui, path)
351 return httprepository(ui, path)
352 return httprepository(ui, path)
General Comments 0
You need to be logged in to leave comments. Login now