##// END OF EJS Templates
fix handling of multiple Content-type headers...
Benoit Boissinot -
r4012:d1e31d7f default
parent child Browse files
Show More
@@ -1,385 +1,389 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 changegroup")
14 demandload(globals(), "errno keepalive tempfile socket changegroup")
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 def zgenerator(f):
117 def zgenerator(f):
118 zd = zlib.decompressobj()
118 zd = zlib.decompressobj()
119 try:
119 try:
120 for chunk in util.filechunkiter(f):
120 for chunk in util.filechunkiter(f):
121 yield zd.decompress(chunk)
121 yield zd.decompress(chunk)
122 except httplib.HTTPException, inst:
122 except httplib.HTTPException, inst:
123 raise IOError(None, _('connection ended unexpectedly'))
123 raise IOError(None, _('connection ended unexpectedly'))
124 yield zd.flush()
124 yield zd.flush()
125
125
126 class httprepository(remoterepository):
126 class httprepository(remoterepository):
127 def __init__(self, ui, path):
127 def __init__(self, ui, path):
128 self.path = path
128 self.path = path
129 self.caps = None
129 self.caps = None
130 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
130 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
131 if query or frag:
131 if query or frag:
132 raise util.Abort(_('unsupported URL component: "%s"') %
132 raise util.Abort(_('unsupported URL component: "%s"') %
133 (query or frag))
133 (query or frag))
134 if not urlpath: urlpath = '/'
134 if not urlpath: urlpath = '/'
135 host, port, user, passwd = netlocsplit(netloc)
135 host, port, user, passwd = netlocsplit(netloc)
136
136
137 # urllib cannot handle URLs with embedded user or passwd
137 # urllib cannot handle URLs with embedded user or passwd
138 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
138 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
139 urlpath, '', ''))
139 urlpath, '', ''))
140 self.ui = ui
140 self.ui = ui
141
141
142 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
142 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
143 # XXX proxyauthinfo = None
143 # XXX proxyauthinfo = None
144 handlers = [httphandler()]
144 handlers = [httphandler()]
145
145
146 if proxyurl:
146 if proxyurl:
147 # proxy can be proper url or host[:port]
147 # proxy can be proper url or host[:port]
148 if not (proxyurl.startswith('http:') or
148 if not (proxyurl.startswith('http:') or
149 proxyurl.startswith('https:')):
149 proxyurl.startswith('https:')):
150 proxyurl = 'http://' + proxyurl + '/'
150 proxyurl = 'http://' + proxyurl + '/'
151 snpqf = urlparse.urlsplit(proxyurl)
151 snpqf = urlparse.urlsplit(proxyurl)
152 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
152 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
153 hpup = netlocsplit(proxynetloc)
153 hpup = netlocsplit(proxynetloc)
154
154
155 proxyhost, proxyport, proxyuser, proxypasswd = hpup
155 proxyhost, proxyport, proxyuser, proxypasswd = hpup
156 if not proxyuser:
156 if not proxyuser:
157 proxyuser = ui.config("http_proxy", "user")
157 proxyuser = ui.config("http_proxy", "user")
158 proxypasswd = ui.config("http_proxy", "passwd")
158 proxypasswd = ui.config("http_proxy", "passwd")
159
159
160 # see if we should use a proxy for this url
160 # see if we should use a proxy for this url
161 no_list = [ "localhost", "127.0.0.1" ]
161 no_list = [ "localhost", "127.0.0.1" ]
162 no_list.extend([p.lower() for
162 no_list.extend([p.lower() for
163 p in ui.configlist("http_proxy", "no")])
163 p in ui.configlist("http_proxy", "no")])
164 no_list.extend([p.strip().lower() for
164 no_list.extend([p.strip().lower() for
165 p in os.getenv("no_proxy", '').split(',')
165 p in os.getenv("no_proxy", '').split(',')
166 if p.strip()])
166 if p.strip()])
167 # "http_proxy.always" config is for running tests on localhost
167 # "http_proxy.always" config is for running tests on localhost
168 if (not ui.configbool("http_proxy", "always") and
168 if (not ui.configbool("http_proxy", "always") and
169 host.lower() in no_list):
169 host.lower() in no_list):
170 ui.debug(_('disabling proxy for %s\n') % host)
170 ui.debug(_('disabling proxy for %s\n') % host)
171 else:
171 else:
172 proxyurl = urlparse.urlunsplit((
172 proxyurl = urlparse.urlunsplit((
173 proxyscheme, netlocunsplit(proxyhost, proxyport,
173 proxyscheme, netlocunsplit(proxyhost, proxyport,
174 proxyuser, proxypasswd or ''),
174 proxyuser, proxypasswd or ''),
175 proxypath, proxyquery, proxyfrag))
175 proxypath, proxyquery, proxyfrag))
176 handlers.append(urllib2.ProxyHandler({scheme: proxyurl}))
176 handlers.append(urllib2.ProxyHandler({scheme: proxyurl}))
177 ui.debug(_('proxying through http://%s:%s\n') %
177 ui.debug(_('proxying through http://%s:%s\n') %
178 (proxyhost, proxyport))
178 (proxyhost, proxyport))
179
179
180 # urllib2 takes proxy values from the environment and those
180 # urllib2 takes proxy values from the environment and those
181 # will take precedence if found, so drop them
181 # will take precedence if found, so drop them
182 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
182 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
183 try:
183 try:
184 if os.environ.has_key(env):
184 if os.environ.has_key(env):
185 del os.environ[env]
185 del os.environ[env]
186 except OSError:
186 except OSError:
187 pass
187 pass
188
188
189 passmgr = passwordmgr(ui)
189 passmgr = passwordmgr(ui)
190 if user:
190 if user:
191 ui.debug(_('http auth: user %s, password %s\n') %
191 ui.debug(_('http auth: user %s, password %s\n') %
192 (user, passwd and '*' * len(passwd) or 'not set'))
192 (user, passwd and '*' * len(passwd) or 'not set'))
193 passmgr.add_password(None, host, user, passwd or '')
193 passmgr.add_password(None, host, user, passwd or '')
194
194
195 handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
195 handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
196 urllib2.HTTPDigestAuthHandler(passmgr)))
196 urllib2.HTTPDigestAuthHandler(passmgr)))
197 opener = urllib2.build_opener(*handlers)
197 opener = urllib2.build_opener(*handlers)
198
198
199 # 1.0 here is the _protocol_ version
199 # 1.0 here is the _protocol_ version
200 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
200 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
201 urllib2.install_opener(opener)
201 urllib2.install_opener(opener)
202
202
203 def url(self):
203 def url(self):
204 return self.path
204 return self.path
205
205
206 # look up capabilities only when needed
206 # look up capabilities only when needed
207
207
208 def get_caps(self):
208 def get_caps(self):
209 if self.caps is None:
209 if self.caps is None:
210 try:
210 try:
211 self.caps = self.do_read('capabilities').split()
211 self.caps = self.do_read('capabilities').split()
212 except hg.RepoError:
212 except hg.RepoError:
213 self.caps = ()
213 self.caps = ()
214 self.ui.debug(_('capabilities: %s\n') %
214 self.ui.debug(_('capabilities: %s\n') %
215 (' '.join(self.caps or ['none'])))
215 (' '.join(self.caps or ['none'])))
216 return self.caps
216 return self.caps
217
217
218 capabilities = property(get_caps)
218 capabilities = property(get_caps)
219
219
220 def lock(self):
220 def lock(self):
221 raise util.Abort(_('operation not supported over http'))
221 raise util.Abort(_('operation not supported over http'))
222
222
223 def do_cmd(self, cmd, **args):
223 def do_cmd(self, cmd, **args):
224 data = args.pop('data', None)
224 data = args.pop('data', None)
225 headers = args.pop('headers', {})
225 headers = args.pop('headers', {})
226 self.ui.debug(_("sending %s command\n") % cmd)
226 self.ui.debug(_("sending %s command\n") % cmd)
227 q = {"cmd": cmd}
227 q = {"cmd": cmd}
228 q.update(args)
228 q.update(args)
229 qs = '?%s' % urllib.urlencode(q)
229 qs = '?%s' % urllib.urlencode(q)
230 cu = "%s%s" % (self._url, qs)
230 cu = "%s%s" % (self._url, qs)
231 try:
231 try:
232 if data:
232 if data:
233 self.ui.debug(_("sending %s bytes\n") %
233 self.ui.debug(_("sending %s bytes\n") %
234 headers.get('content-length', 'X'))
234 headers.get('content-length', 'X'))
235 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
235 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
236 except urllib2.HTTPError, inst:
236 except urllib2.HTTPError, inst:
237 if inst.code == 401:
237 if inst.code == 401:
238 raise util.Abort(_('authorization failed'))
238 raise util.Abort(_('authorization failed'))
239 raise
239 raise
240 except httplib.HTTPException, inst:
240 except httplib.HTTPException, inst:
241 self.ui.debug(_('http error while sending %s command\n') % cmd)
241 self.ui.debug(_('http error while sending %s command\n') % cmd)
242 self.ui.print_exc()
242 self.ui.print_exc()
243 raise IOError(None, inst)
243 raise IOError(None, inst)
244 except IndexError:
244 except IndexError:
245 # this only happens with Python 2.3, later versions raise URLError
245 # this only happens with Python 2.3, later versions raise URLError
246 raise util.Abort(_('http error, possibly caused by proxy setting'))
246 raise util.Abort(_('http error, possibly caused by proxy setting'))
247 # record the url we got redirected to
247 # record the url we got redirected to
248 resp_url = resp.geturl()
248 resp_url = resp.geturl()
249 if resp_url.endswith(qs):
249 if resp_url.endswith(qs):
250 resp_url = resp_url[:-len(qs)]
250 resp_url = resp_url[:-len(qs)]
251 if self._url != resp_url:
251 if self._url != resp_url:
252 self.ui.status(_('real URL is %s\n') % resp_url)
252 self.ui.status(_('real URL is %s\n') % resp_url)
253 self._url = resp_url
253 self._url = resp_url
254 try:
254 try:
255 proto = resp.getheader('content-type')
255 proto = resp.getheader('content-type')
256 except AttributeError:
256 except AttributeError:
257 proto = resp.headers['content-type']
257 proto = resp.headers['content-type']
258
258
259 # accept old "text/plain" and "application/hg-changegroup" for now
259 # accept old "text/plain" and "application/hg-changegroup" for now
260 if not proto.startswith('application/mercurial') and \
260 if not proto.startswith('application/mercurial-') and \
261 not proto.startswith('text/plain') and \
261 not proto.startswith('text/plain') and \
262 not proto.startswith('application/hg-changegroup'):
262 not proto.startswith('application/hg-changegroup'):
263 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
263 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
264 self._url)
264 self._url)
265
265
266 if proto.startswith('application/mercurial'):
266 if proto.startswith('application/mercurial-'):
267 version = proto[22:]
267 try:
268 if float(version) > 0.1:
268 version = float(proto[22:])
269 except ValueError:
270 raise hg.RepoError(_("'%s' sent a broken Content-type "
271 "header (%s)") % (self._url, proto))
272 if version > 0.1:
269 raise hg.RepoError(_("'%s' uses newer protocol %s") %
273 raise hg.RepoError(_("'%s' uses newer protocol %s") %
270 (self._url, version))
274 (self._url, version))
271
275
272 return resp
276 return resp
273
277
274 def do_read(self, cmd, **args):
278 def do_read(self, cmd, **args):
275 fp = self.do_cmd(cmd, **args)
279 fp = self.do_cmd(cmd, **args)
276 try:
280 try:
277 return fp.read()
281 return fp.read()
278 finally:
282 finally:
279 # if using keepalive, allow connection to be reused
283 # if using keepalive, allow connection to be reused
280 fp.close()
284 fp.close()
281
285
282 def lookup(self, key):
286 def lookup(self, key):
283 d = self.do_cmd("lookup", key = key).read()
287 d = self.do_cmd("lookup", key = key).read()
284 success, data = d[:-1].split(' ', 1)
288 success, data = d[:-1].split(' ', 1)
285 if int(success):
289 if int(success):
286 return bin(data)
290 return bin(data)
287 raise hg.RepoError(data)
291 raise hg.RepoError(data)
288
292
289 def heads(self):
293 def heads(self):
290 d = self.do_read("heads")
294 d = self.do_read("heads")
291 try:
295 try:
292 return map(bin, d[:-1].split(" "))
296 return map(bin, d[:-1].split(" "))
293 except:
297 except:
294 raise util.UnexpectedOutput(_("unexpected response:"), d)
298 raise util.UnexpectedOutput(_("unexpected response:"), d)
295
299
296 def branches(self, nodes):
300 def branches(self, nodes):
297 n = " ".join(map(hex, nodes))
301 n = " ".join(map(hex, nodes))
298 d = self.do_read("branches", nodes=n)
302 d = self.do_read("branches", nodes=n)
299 try:
303 try:
300 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
304 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
301 return br
305 return br
302 except:
306 except:
303 raise util.UnexpectedOutput(_("unexpected response:"), d)
307 raise util.UnexpectedOutput(_("unexpected response:"), d)
304
308
305 def between(self, pairs):
309 def between(self, pairs):
306 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
310 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
307 d = self.do_read("between", pairs=n)
311 d = self.do_read("between", pairs=n)
308 try:
312 try:
309 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
313 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
310 return p
314 return p
311 except:
315 except:
312 raise util.UnexpectedOutput(_("unexpected response:"), d)
316 raise util.UnexpectedOutput(_("unexpected response:"), d)
313
317
314 def changegroup(self, nodes, kind):
318 def changegroup(self, nodes, kind):
315 n = " ".join(map(hex, nodes))
319 n = " ".join(map(hex, nodes))
316 f = self.do_cmd("changegroup", roots=n)
320 f = self.do_cmd("changegroup", roots=n)
317 return util.chunkbuffer(zgenerator(f))
321 return util.chunkbuffer(zgenerator(f))
318
322
319 def changegroupsubset(self, bases, heads, source):
323 def changegroupsubset(self, bases, heads, source):
320 baselst = " ".join([hex(n) for n in bases])
324 baselst = " ".join([hex(n) for n in bases])
321 headlst = " ".join([hex(n) for n in heads])
325 headlst = " ".join([hex(n) for n in heads])
322 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
326 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
323 return util.chunkbuffer(zgenerator(f))
327 return util.chunkbuffer(zgenerator(f))
324
328
325 def unbundle(self, cg, heads, source):
329 def unbundle(self, cg, heads, source):
326 # have to stream bundle to a temp file because we do not have
330 # have to stream bundle to a temp file because we do not have
327 # http 1.1 chunked transfer.
331 # http 1.1 chunked transfer.
328
332
329 type = ""
333 type = ""
330 types = self.capable('unbundle')
334 types = self.capable('unbundle')
331 # servers older than d1b16a746db6 will send 'unbundle' as a
335 # servers older than d1b16a746db6 will send 'unbundle' as a
332 # boolean capability
336 # boolean capability
333 try:
337 try:
334 types = types.split(',')
338 types = types.split(',')
335 except AttributeError:
339 except AttributeError:
336 types = [""]
340 types = [""]
337 if types:
341 if types:
338 for x in types:
342 for x in types:
339 if x in changegroup.bundletypes:
343 if x in changegroup.bundletypes:
340 type = x
344 type = x
341 break
345 break
342
346
343 tempname = changegroup.writebundle(cg, None, type)
347 tempname = changegroup.writebundle(cg, None, type)
344 fp = file(tempname, "rb")
348 fp = file(tempname, "rb")
345 try:
349 try:
346 length = os.stat(tempname).st_size
350 length = os.stat(tempname).st_size
347 try:
351 try:
348 rfp = self.do_cmd(
352 rfp = self.do_cmd(
349 'unbundle', data=fp,
353 'unbundle', data=fp,
350 headers={'content-length': str(length),
354 headers={'content-length': str(length),
351 'content-type': 'application/octet-stream'},
355 'content-type': 'application/octet-stream'},
352 heads=' '.join(map(hex, heads)))
356 heads=' '.join(map(hex, heads)))
353 try:
357 try:
354 ret = int(rfp.readline())
358 ret = int(rfp.readline())
355 self.ui.write(rfp.read())
359 self.ui.write(rfp.read())
356 return ret
360 return ret
357 finally:
361 finally:
358 rfp.close()
362 rfp.close()
359 except socket.error, err:
363 except socket.error, err:
360 if err[0] in (errno.ECONNRESET, errno.EPIPE):
364 if err[0] in (errno.ECONNRESET, errno.EPIPE):
361 raise util.Abort(_('push failed: %s') % err[1])
365 raise util.Abort(_('push failed: %s') % err[1])
362 raise util.Abort(err[1])
366 raise util.Abort(err[1])
363 finally:
367 finally:
364 fp.close()
368 fp.close()
365 os.unlink(tempname)
369 os.unlink(tempname)
366
370
367 def stream_out(self):
371 def stream_out(self):
368 return self.do_cmd('stream_out')
372 return self.do_cmd('stream_out')
369
373
370 class httpsrepository(httprepository):
374 class httpsrepository(httprepository):
371 def __init__(self, ui, path):
375 def __init__(self, ui, path):
372 if not has_https:
376 if not has_https:
373 raise util.Abort(_('Python support for SSL and HTTPS '
377 raise util.Abort(_('Python support for SSL and HTTPS '
374 'is not installed'))
378 'is not installed'))
375 httprepository.__init__(self, ui, path)
379 httprepository.__init__(self, ui, path)
376
380
377 def instance(ui, path, create):
381 def instance(ui, path, create):
378 if create:
382 if create:
379 raise util.Abort(_('cannot create new http repository'))
383 raise util.Abort(_('cannot create new http repository'))
380 if path.startswith('hg:'):
384 if path.startswith('hg:'):
381 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
385 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
382 path = 'http:' + path[3:]
386 path = 'http:' + path[3:]
383 if path.startswith('https:'):
387 if path.startswith('https:'):
384 return httpsrepository(ui, path)
388 return httpsrepository(ui, path)
385 return httprepository(ui, path)
389 return httprepository(ui, path)
General Comments 0
You need to be logged in to leave comments. Login now