Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/httprepo.py @ 2465:c91118f425d0
push over http: client support.
stream bundle data using PUT request.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Tue, 20 Jun 2006 15:17:28 -0700 |
parents | cd00531ecc16 |
children | 4e78dc71d946 |
comparison
equal
deleted
inserted
replaced
2464:09b1c9ef317c | 2465:c91118f425d0 |
---|---|
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(), "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)) |
175 except httplib.HTTPException, inst: | 195 except httplib.HTTPException, inst: |
176 self.ui.debug(_('http error while sending %s command\n') % cmd) | 196 self.ui.debug(_('http error while sending %s command\n') % cmd) |
177 self.ui.print_exc() | 197 self.ui.print_exc() |
178 raise IOError(None, inst) | 198 raise IOError(None, inst) |
179 try: | 199 try: |
247 yield zd.flush() | 267 yield zd.flush() |
248 | 268 |
249 return util.chunkbuffer(zgenerator(util.filechunkiter(f))) | 269 return util.chunkbuffer(zgenerator(util.filechunkiter(f))) |
250 | 270 |
251 def unbundle(self, cg, heads, source): | 271 def unbundle(self, cg, heads, source): |
252 raise util.Abort(_('operation not supported over http')) | 272 # have to stream bundle to a temp file because we do not have |
273 # http 1.1 chunked transfer. | |
274 | |
275 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-') | |
276 fp = os.fdopen(fd, 'wb+') | |
277 try: | |
278 for chunk in util.filechunkiter(cg): | |
279 fp.write(chunk) | |
280 length = fp.tell() | |
281 rfp = self.do_cmd( | |
282 'unbundle', data=fp, | |
283 headers={'content-length': length, | |
284 'content-type': 'application/octet-stream'}, | |
285 heads=' '.join(map(hex, heads))) | |
286 try: | |
287 ret = int(rfp.readline()) | |
288 self.ui.write(rfp.read()) | |
289 return ret | |
290 finally: | |
291 rfp.close() | |
292 finally: | |
293 fp.close() | |
294 os.unlink(tempname) | |
253 | 295 |
254 class httpsrepository(httprepository): | 296 class httpsrepository(httprepository): |
255 pass | 297 pass |