comparison mercurial/httprepo.py @ 2471:6904e1ef8ad1

merge with crew.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Tue, 20 Jun 2006 23:58:45 -0700
parents 4e78dc71d946
children eabcda3ed0dd
comparison
equal deleted inserted replaced
2470:fe1689273f84 2471:6904e1ef8ad1
8 from node import * 8 from node import *
9 from remoterepo import * 9 from remoterepo import *
10 from i18n import gettext as _ 10 from i18n import gettext as _
11 from demandload import * 11 from demandload import *
12 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib") 12 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
13 demandload(globals(), "keepalive") 13 demandload(globals(), "errno keepalive tempfile socket")
14 14
15 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm): 15 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
16 def __init__(self, ui): 16 def __init__(self, ui):
17 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self) 17 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
18 self.ui = ui 18 self.ui = ui
67 else: 67 else:
68 userpass = urllib.quote(user) 68 userpass = urllib.quote(user)
69 return userpass + '@' + hostport 69 return userpass + '@' + hostport
70 return hostport 70 return hostport
71 71
72 class httpconnection(keepalive.HTTPConnection):
73 # must be able to send big bundle as stream.
74
75 def send(self, data):
76 if isinstance(data, str):
77 keepalive.HTTPConnection.send(self, data)
78 else:
79 # if auth required, some data sent twice, so rewind here
80 data.seek(0)
81 for chunk in util.filechunkiter(data):
82 keepalive.HTTPConnection.send(self, chunk)
83
84 class httphandler(keepalive.HTTPHandler):
85 def http_open(self, req):
86 return self.do_open(httpconnection, req)
87
72 class httprepository(remoterepository): 88 class httprepository(remoterepository):
73 def __init__(self, ui, path): 89 def __init__(self, ui, path):
74 self.caps = None 90 self.caps = None
75 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) 91 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
76 if query or frag: 92 if query or frag:
84 urlpath, '', '')) 100 urlpath, '', ''))
85 self.ui = ui 101 self.ui = ui
86 102
87 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') 103 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
88 proxyauthinfo = None 104 proxyauthinfo = None
89 handler = keepalive.HTTPHandler() 105 handler = httphandler()
90 106
91 if proxyurl: 107 if proxyurl:
92 # proxy can be proper url or host[:port] 108 # proxy can be proper url or host[:port]
93 if not (proxyurl.startswith('http:') or 109 if not (proxyurl.startswith('http:') or
94 proxyurl.startswith('https:')): 110 proxyurl.startswith('https:')):
152 if self.caps is None: 168 if self.caps is None:
153 try: 169 try:
154 self.caps = self.do_read('capabilities').split() 170 self.caps = self.do_read('capabilities').split()
155 except hg.RepoError: 171 except hg.RepoError:
156 self.caps = () 172 self.caps = ()
173 self.ui.debug(_('capabilities: %s\n') %
174 (' '.join(self.caps or ['none'])))
157 return self.caps 175 return self.caps
158 176
159 capabilities = property(get_caps) 177 capabilities = property(get_caps)
160 178
161 def dev(self): 179 def dev(self):
163 181
164 def lock(self): 182 def lock(self):
165 raise util.Abort(_('operation not supported over http')) 183 raise util.Abort(_('operation not supported over http'))
166 184
167 def do_cmd(self, cmd, **args): 185 def do_cmd(self, cmd, **args):
186 data = args.pop('data', None)
187 headers = args.pop('headers', {})
168 self.ui.debug(_("sending %s command\n") % cmd) 188 self.ui.debug(_("sending %s command\n") % cmd)
169 q = {"cmd": cmd} 189 q = {"cmd": cmd}
170 q.update(args) 190 q.update(args)
171 qs = urllib.urlencode(q) 191 qs = urllib.urlencode(q)
172 cu = "%s?%s" % (self.url, qs) 192 cu = "%s?%s" % (self.url, qs)
173 try: 193 try:
174 resp = urllib2.urlopen(cu) 194 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
195 except urllib2.HTTPError, inst:
196 if inst.code == 401:
197 raise util.Abort(_('authorization failed'))
198 raise
175 except httplib.HTTPException, inst: 199 except httplib.HTTPException, inst:
176 self.ui.debug(_('http error while sending %s command\n') % cmd) 200 self.ui.debug(_('http error while sending %s command\n') % cmd)
177 self.ui.print_exc() 201 self.ui.print_exc()
178 raise IOError(None, inst) 202 raise IOError(None, inst)
179 try: 203 try:
247 yield zd.flush() 271 yield zd.flush()
248 272
249 return util.chunkbuffer(zgenerator(util.filechunkiter(f))) 273 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
250 274
251 def unbundle(self, cg, heads, source): 275 def unbundle(self, cg, heads, source):
252 raise util.Abort(_('operation not supported over http')) 276 # have to stream bundle to a temp file because we do not have
277 # http 1.1 chunked transfer.
278
279 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
280 fp = os.fdopen(fd, 'wb+')
281 try:
282 for chunk in util.filechunkiter(cg):
283 fp.write(chunk)
284 length = fp.tell()
285 try:
286 rfp = self.do_cmd(
287 'unbundle', data=fp,
288 headers={'content-length': length,
289 'content-type': 'application/octet-stream'},
290 heads=' '.join(map(hex, heads)))
291 try:
292 ret = int(rfp.readline())
293 self.ui.write(rfp.read())
294 return ret
295 finally:
296 rfp.close()
297 except socket.error, err:
298 if err[0] in (errno.ECONNRESET, errno.EPIPE):
299 raise util.Abort(_('push failed: %s'), err[1])
300 raise util.Abort(err[1])
301 finally:
302 fp.close()
303 os.unlink(tempname)
253 304
254 class httpsrepository(httprepository): 305 class httpsrepository(httprepository):
255 pass 306 pass