[PATCH 04 of 11] httppeer: use compression engine API for decompressing responses
Augie Fackler
raf at durin42.com
Mon Nov 21 17:18:17 EST 2016
On Sun, Nov 20, 2016 at 02:23:41PM -0800, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1479678953 28800
> # Sun Nov 20 13:55:53 2016 -0800
> # Node ID da1caf5b703a641f0167ece15fdff167a1343ec1
> # Parent 0bef0b8fb9f44ed8568df6cfeabf162aa12b211e
> httppeer: use compression engine API for decompressing responses
>
> In preparation for supporting multiple compression formats on the
> wire protocol, we need all users of the wire protocol to use
> compression engine APIs.
>
> This commit ports the HTTP wire protocol client to use the
> compression engine API.
>
> The code for handling the HTTPException is a bit hacky. Essentially,
> HTTPException could be thrown by any read() from the socket. However,
> as part of porting the API, we no longer have a generator wrapping
> the socket and we don't have a single place where we can trap the
> exception. We solve this by introducing a proxy class that intercepts
> read() and converts the exception appropriately.
>
> In the future, we could introduce a new compression engine API that
> supports emitting a generator of decompressed chunks. This would
> eliminate the need for the proxy class. As I said when I introduced
> the decompressorreader() API, I'm not fond of it and would support
> transitioning to something better. This can be done as a follow-up,
> preferably once all the code is using the compression engine API and
> we have a better idea of the API needs of all the consumers.
>
> diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
> --- a/mercurial/httppeer.py
> +++ b/mercurial/httppeer.py
> @@ -12,7 +12,6 @@ import errno
> import os
> import socket
> import tempfile
> -import zlib
>
> from .i18n import _
> from .node import nullid
> @@ -30,16 +29,26 @@ httplib = util.httplib
> urlerr = util.urlerr
> urlreq = util.urlreq
>
> -def zgenerator(f):
> - zd = zlib.decompressobj()
> +# FUTURE: consider refactoring this API to use generators. This will
> +# require a compression engine API to emit generators.
> +def decompressresponse(response, engine):
> try:
> - for chunk in util.filechunkiter(f):
> - while chunk:
> - yield zd.decompress(chunk, 2**18)
> - chunk = zd.unconsumed_tail
> + reader = engine.decompressorreader(response)
> except httplib.HTTPException:
> raise IOError(None, _('connection ended unexpectedly'))
> - yield zd.flush()
> +
> + # We need to wrap reader.read() so HTTPException on subsequent
> + # reads is also converted.
> + origread = reader.read
> + class readerproxy(reader.__class__):
> + def read(self, *args, **kwargs):
> + try:
> + return origread(*args, **kwargs)
nit: I think you could use super(readerproxy, self).read() here (but
do this as a follow-up if you agree with the idea)
> + except httplib.HTTPException:
> + raise IOError(None, _('connection ended unexpectedly'))
> +
> + reader.__class__ = readerproxy
> + return reader
>
> class httppeer(wireproto.wirepeer):
> def __init__(self, ui, path):
> @@ -202,7 +211,7 @@ class httppeer(wireproto.wirepeer):
> (safeurl, version))
>
> if _compressible:
> - return util.chunkbuffer(zgenerator(resp))
> + return decompressresponse(resp, util.compengines['zlib'])
>
> return resp
>
More information about the Mercurial-devel
mailing list