##// END OF EJS Templates
Subclass file with a __len__ method instead of setting Content-length...
Benoit Boissinot -
r4025:d8b3edf8 default
parent child Browse files
Show More
@@ -1,389 +1,387 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 httpsendfile(file):
80 # must be able to send big bundle as stream.
80 def __len__(self):
81 return os.fstat(self.fileno()).st_size
81
82
82 def send(self, data):
83 def _gen_sendfile(connection):
83 if isinstance(data, str):
84 def _sendfile(self, data):
84 keepalive.HTTPConnection.send(self, data)
85 # send a file
85 else:
86 if isinstance(data, httpsendfile):
86 # if auth required, some data sent twice, so rewind here
87 # if auth required, some data sent twice, so rewind here
87 data.seek(0)
88 data.seek(0)
88 for chunk in util.filechunkiter(data):
89 for chunk in util.filechunkiter(data):
89 keepalive.HTTPConnection.send(self, chunk)
90 connection.send(self, chunk)
91 else:
92 connection.send(self, data)
93 return _sendfile
94
95 class httpconnection(keepalive.HTTPConnection):
96 # must be able to send big bundle as stream.
97 send = _gen_sendfile(keepalive.HTTPConnection)
90
98
91 class basehttphandler(keepalive.HTTPHandler):
99 class basehttphandler(keepalive.HTTPHandler):
92 def http_open(self, req):
100 def http_open(self, req):
93 return self.do_open(httpconnection, req)
101 return self.do_open(httpconnection, req)
94
102
95 has_https = hasattr(urllib2, 'HTTPSHandler')
103 has_https = hasattr(urllib2, 'HTTPSHandler')
96 if has_https:
104 if has_https:
97 class httpsconnection(httplib.HTTPSConnection):
105 class httpsconnection(httplib.HTTPSConnection):
98 response_class = keepalive.HTTPResponse
106 response_class = keepalive.HTTPResponse
99 # must be able to send big bundle as stream.
107 # must be able to send big bundle as stream.
100
108 send = _gen_sendfile(httplib.HTTPSConnection)
101 def send(self, data):
102 if isinstance(data, str):
103 httplib.HTTPSConnection.send(self, data)
104 else:
105 # if auth required, some data sent twice, so rewind here
106 data.seek(0)
107 for chunk in util.filechunkiter(data):
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 try:
267 try:
268 version = float(proto[22:])
268 version = float(proto[22:])
269 except ValueError:
269 except ValueError:
270 raise hg.RepoError(_("'%s' sent a broken Content-type "
270 raise hg.RepoError(_("'%s' sent a broken Content-type "
271 "header (%s)") % (self._url, proto))
271 "header (%s)") % (self._url, proto))
272 if version > 0.1:
272 if version > 0.1:
273 raise hg.RepoError(_("'%s' uses newer protocol %s") %
273 raise hg.RepoError(_("'%s' uses newer protocol %s") %
274 (self._url, version))
274 (self._url, version))
275
275
276 return resp
276 return resp
277
277
278 def do_read(self, cmd, **args):
278 def do_read(self, cmd, **args):
279 fp = self.do_cmd(cmd, **args)
279 fp = self.do_cmd(cmd, **args)
280 try:
280 try:
281 return fp.read()
281 return fp.read()
282 finally:
282 finally:
283 # if using keepalive, allow connection to be reused
283 # if using keepalive, allow connection to be reused
284 fp.close()
284 fp.close()
285
285
286 def lookup(self, key):
286 def lookup(self, key):
287 d = self.do_cmd("lookup", key = key).read()
287 d = self.do_cmd("lookup", key = key).read()
288 success, data = d[:-1].split(' ', 1)
288 success, data = d[:-1].split(' ', 1)
289 if int(success):
289 if int(success):
290 return bin(data)
290 return bin(data)
291 raise hg.RepoError(data)
291 raise hg.RepoError(data)
292
292
293 def heads(self):
293 def heads(self):
294 d = self.do_read("heads")
294 d = self.do_read("heads")
295 try:
295 try:
296 return map(bin, d[:-1].split(" "))
296 return map(bin, d[:-1].split(" "))
297 except:
297 except:
298 raise util.UnexpectedOutput(_("unexpected response:"), d)
298 raise util.UnexpectedOutput(_("unexpected response:"), d)
299
299
300 def branches(self, nodes):
300 def branches(self, nodes):
301 n = " ".join(map(hex, nodes))
301 n = " ".join(map(hex, nodes))
302 d = self.do_read("branches", nodes=n)
302 d = self.do_read("branches", nodes=n)
303 try:
303 try:
304 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
304 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
305 return br
305 return br
306 except:
306 except:
307 raise util.UnexpectedOutput(_("unexpected response:"), d)
307 raise util.UnexpectedOutput(_("unexpected response:"), d)
308
308
309 def between(self, pairs):
309 def between(self, pairs):
310 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
310 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
311 d = self.do_read("between", pairs=n)
311 d = self.do_read("between", pairs=n)
312 try:
312 try:
313 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() ]
314 return p
314 return p
315 except:
315 except:
316 raise util.UnexpectedOutput(_("unexpected response:"), d)
316 raise util.UnexpectedOutput(_("unexpected response:"), d)
317
317
318 def changegroup(self, nodes, kind):
318 def changegroup(self, nodes, kind):
319 n = " ".join(map(hex, nodes))
319 n = " ".join(map(hex, nodes))
320 f = self.do_cmd("changegroup", roots=n)
320 f = self.do_cmd("changegroup", roots=n)
321 return util.chunkbuffer(zgenerator(f))
321 return util.chunkbuffer(zgenerator(f))
322
322
323 def changegroupsubset(self, bases, heads, source):
323 def changegroupsubset(self, bases, heads, source):
324 baselst = " ".join([hex(n) for n in bases])
324 baselst = " ".join([hex(n) for n in bases])
325 headlst = " ".join([hex(n) for n in heads])
325 headlst = " ".join([hex(n) for n in heads])
326 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
326 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
327 return util.chunkbuffer(zgenerator(f))
327 return util.chunkbuffer(zgenerator(f))
328
328
329 def unbundle(self, cg, heads, source):
329 def unbundle(self, cg, heads, source):
330 # 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
331 # http 1.1 chunked transfer.
331 # http 1.1 chunked transfer.
332
332
333 type = ""
333 type = ""
334 types = self.capable('unbundle')
334 types = self.capable('unbundle')
335 # servers older than d1b16a746db6 will send 'unbundle' as a
335 # servers older than d1b16a746db6 will send 'unbundle' as a
336 # boolean capability
336 # boolean capability
337 try:
337 try:
338 types = types.split(',')
338 types = types.split(',')
339 except AttributeError:
339 except AttributeError:
340 types = [""]
340 types = [""]
341 if types:
341 if types:
342 for x in types:
342 for x in types:
343 if x in changegroup.bundletypes:
343 if x in changegroup.bundletypes:
344 type = x
344 type = x
345 break
345 break
346
346
347 tempname = changegroup.writebundle(cg, None, type)
347 tempname = changegroup.writebundle(cg, None, type)
348 fp = file(tempname, "rb")
348 fp = httpsendfile(tempname, "rb")
349 try:
349 try:
350 length = os.stat(tempname).st_size
351 try:
350 try:
352 rfp = self.do_cmd(
351 rfp = self.do_cmd(
353 'unbundle', data=fp,
352 'unbundle', data=fp,
354 headers={'content-length': str(length),
353 headers={'content-type': 'application/octet-stream'},
355 'content-type': 'application/octet-stream'},
356 heads=' '.join(map(hex, heads)))
354 heads=' '.join(map(hex, heads)))
357 try:
355 try:
358 ret = int(rfp.readline())
356 ret = int(rfp.readline())
359 self.ui.write(rfp.read())
357 self.ui.write(rfp.read())
360 return ret
358 return ret
361 finally:
359 finally:
362 rfp.close()
360 rfp.close()
363 except socket.error, err:
361 except socket.error, err:
364 if err[0] in (errno.ECONNRESET, errno.EPIPE):
362 if err[0] in (errno.ECONNRESET, errno.EPIPE):
365 raise util.Abort(_('push failed: %s') % err[1])
363 raise util.Abort(_('push failed: %s') % err[1])
366 raise util.Abort(err[1])
364 raise util.Abort(err[1])
367 finally:
365 finally:
368 fp.close()
366 fp.close()
369 os.unlink(tempname)
367 os.unlink(tempname)
370
368
371 def stream_out(self):
369 def stream_out(self):
372 return self.do_cmd('stream_out')
370 return self.do_cmd('stream_out')
373
371
374 class httpsrepository(httprepository):
372 class httpsrepository(httprepository):
375 def __init__(self, ui, path):
373 def __init__(self, ui, path):
376 if not has_https:
374 if not has_https:
377 raise util.Abort(_('Python support for SSL and HTTPS '
375 raise util.Abort(_('Python support for SSL and HTTPS '
378 'is not installed'))
376 'is not installed'))
379 httprepository.__init__(self, ui, path)
377 httprepository.__init__(self, ui, path)
380
378
381 def instance(ui, path, create):
379 def instance(ui, path, create):
382 if create:
380 if create:
383 raise util.Abort(_('cannot create new http repository'))
381 raise util.Abort(_('cannot create new http repository'))
384 if path.startswith('hg:'):
382 if path.startswith('hg:'):
385 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
383 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
386 path = 'http:' + path[3:]
384 path = 'http:' + path[3:]
387 if path.startswith('https:'):
385 if path.startswith('https:'):
388 return httpsrepository(ui, path)
386 return httpsrepository(ui, path)
389 return httprepository(ui, path)
387 return httprepository(ui, path)
General Comments 0
You need to be logged in to leave comments. Login now