comparison mercurial/httprepo.py @ 2435:ff2bac730b99

http client: support persistent connections. uses keepalive module from urlgrabber package. tested against "hg serve", cgi server, and through http proxy. used ethereal to verify that only one tcp connection used during entire "hg pull" sequence. if server supports keepalive, this makes latency of "hg pull" much lower.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Thu, 15 Jun 2006 12:57:59 -0700
parents 3f24bc5dee81
children e8c4f3d3df8c
comparison
equal deleted inserted replaced
2434:a2df85adface 2435:ff2bac730b99
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 14
14 class passwordmgr(urllib2.HTTPPasswordMgr): 15 class passwordmgr(urllib2.HTTPPasswordMgr):
15 def __init__(self, ui): 16 def __init__(self, ui):
16 urllib2.HTTPPasswordMgr.__init__(self) 17 urllib2.HTTPPasswordMgr.__init__(self)
17 self.ui = ui 18 self.ui = ui
82 urlpath, '', '')) 83 urlpath, '', ''))
83 self.ui = ui 84 self.ui = ui
84 85
85 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') 86 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
86 proxyauthinfo = None 87 proxyauthinfo = None
87 handler = urllib2.BaseHandler() 88 handler = keepalive.HTTPHandler()
88 89
89 if proxyurl: 90 if proxyurl:
90 # proxy can be proper url or host[:port] 91 # proxy can be proper url or host[:port]
91 if not (proxyurl.startswith('http:') or 92 if not (proxyurl.startswith('http:') or
92 proxyurl.startswith('https:')): 93 proxyurl.startswith('https:')):
159 resp = urllib2.urlopen(cu) 160 resp = urllib2.urlopen(cu)
160 except httplib.HTTPException, inst: 161 except httplib.HTTPException, inst:
161 self.ui.debug(_('http error while sending %s command\n') % cmd) 162 self.ui.debug(_('http error while sending %s command\n') % cmd)
162 self.ui.print_exc() 163 self.ui.print_exc()
163 raise IOError(None, inst) 164 raise IOError(None, inst)
164 proto = resp.headers['content-type'] 165 try:
166 proto = resp.getheader('content-type')
167 except AttributeError:
168 proto = resp.headers['content-type']
165 169
166 # accept old "text/plain" and "application/hg-changegroup" for now 170 # accept old "text/plain" and "application/hg-changegroup" for now
167 if not proto.startswith('application/mercurial') and \ 171 if not proto.startswith('application/mercurial') and \
168 not proto.startswith('text/plain') and \ 172 not proto.startswith('text/plain') and \
169 not proto.startswith('application/hg-changegroup'): 173 not proto.startswith('application/hg-changegroup'):
176 raise hg.RepoError(_("'%s' uses newer protocol %s") % 180 raise hg.RepoError(_("'%s' uses newer protocol %s") %
177 (self.url, version)) 181 (self.url, version))
178 182
179 return resp 183 return resp
180 184
185 def do_read(self, cmd, **args):
186 fp = self.do_cmd(cmd, **args)
187 try:
188 return fp.read()
189 finally:
190 # if using keepalive, allow connection to be reused
191 fp.close()
192
181 def heads(self): 193 def heads(self):
182 d = self.do_cmd("heads").read() 194 d = self.do_read("heads")
183 try: 195 try:
184 return map(bin, d[:-1].split(" ")) 196 return map(bin, d[:-1].split(" "))
185 except: 197 except:
186 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n") 198 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
187 raise 199 raise
188 200
189 def branches(self, nodes): 201 def branches(self, nodes):
190 n = " ".join(map(hex, nodes)) 202 n = " ".join(map(hex, nodes))
191 d = self.do_cmd("branches", nodes=n).read() 203 d = self.do_read("branches", nodes=n)
192 try: 204 try:
193 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ] 205 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
194 return br 206 return br
195 except: 207 except:
196 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n") 208 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
197 raise 209 raise
198 210
199 def between(self, pairs): 211 def between(self, pairs):
200 n = "\n".join(["-".join(map(hex, p)) for p in pairs]) 212 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
201 d = self.do_cmd("between", pairs=n).read() 213 d = self.do_read("between", pairs=n)
202 try: 214 try:
203 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ] 215 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
204 return p 216 return p
205 except: 217 except:
206 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n") 218 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")