28 ) |
28 ) |
29 |
29 |
30 httplib = util.httplib |
30 httplib = util.httplib |
31 urlerr = util.urlerr |
31 urlerr = util.urlerr |
32 urlreq = util.urlreq |
32 urlreq = util.urlreq |
33 |
|
34 # FUTURE: consider refactoring this API to use generators. This will |
|
35 # require a compression engine API to emit generators. |
|
36 def decompressresponse(response, engine): |
|
37 try: |
|
38 reader = engine.decompressorreader(response) |
|
39 except httplib.HTTPException: |
|
40 raise IOError(None, _('connection ended unexpectedly')) |
|
41 |
|
42 # We need to wrap reader.read() so HTTPException on subsequent |
|
43 # reads is also converted. |
|
44 # Ideally we'd use super() here. However, if ``reader`` isn't a new-style |
|
45 # class, this can raise: |
|
46 # TypeError: super() argument 1 must be type, not classobj |
|
47 origread = reader.read |
|
48 class readerproxy(reader.__class__): |
|
49 def read(self, *args, **kwargs): |
|
50 try: |
|
51 return origread(*args, **kwargs) |
|
52 except httplib.HTTPException: |
|
53 raise IOError(None, _('connection ended unexpectedly')) |
|
54 |
|
55 reader.__class__ = readerproxy |
|
56 return reader |
|
57 |
33 |
58 def encodevalueinheaders(value, header, limit): |
34 def encodevalueinheaders(value, header, limit): |
59 """Encode a string value into multiple HTTP headers. |
35 """Encode a string value into multiple HTTP headers. |
60 |
36 |
61 ``value`` will be encoded into 1 or more HTTP headers with the names |
37 ``value`` will be encoded into 1 or more HTTP headers with the names |
295 version_info = tuple([int(n) for n in version.split('.')]) |
271 version_info = tuple([int(n) for n in version.split('.')]) |
296 except ValueError: |
272 except ValueError: |
297 raise error.RepoError(_("'%s' sent a broken Content-Type " |
273 raise error.RepoError(_("'%s' sent a broken Content-Type " |
298 "header (%s)") % (safeurl, proto)) |
274 "header (%s)") % (safeurl, proto)) |
299 |
275 |
|
276 # TODO consider switching to a decompression reader that uses |
|
277 # generators. |
300 if version_info == (0, 1): |
278 if version_info == (0, 1): |
301 if _compressible: |
279 if _compressible: |
302 return decompressresponse(resp, util.compengines['zlib']) |
280 return util.compengines['zlib'].decompressorreader(resp) |
303 return resp |
281 return resp |
304 elif version_info == (0, 2): |
282 elif version_info == (0, 2): |
305 # application/mercurial-0.2 always identifies the compression |
283 # application/mercurial-0.2 always identifies the compression |
306 # engine in the payload header. |
284 # engine in the payload header. |
307 elen = struct.unpack('B', resp.read(1))[0] |
285 elen = struct.unpack('B', resp.read(1))[0] |
308 ename = resp.read(elen) |
286 ename = resp.read(elen) |
309 engine = util.compengines.forwiretype(ename) |
287 engine = util.compengines.forwiretype(ename) |
310 return decompressresponse(resp, engine) |
288 return engine.decompressorreader(resp) |
311 else: |
289 else: |
312 raise error.RepoError(_("'%s' uses newer protocol %s") % |
290 raise error.RepoError(_("'%s' uses newer protocol %s") % |
313 (safeurl, version)) |
291 (safeurl, version)) |
314 |
292 |
315 if _compressible: |
293 if _compressible: |
316 return decompressresponse(resp, util.compengines['zlib']) |
294 return util.compengines['zlib'].decompressorreader(resp) |
317 |
295 |
318 return resp |
296 return resp |
319 |
297 |
320 def _call(self, cmd, **args): |
298 def _call(self, cmd, **args): |
321 fp = self._callstream(cmd, **args) |
299 fp = self._callstream(cmd, **args) |