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:')): |
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 |