commit 31490d6b2395abd4459f794863b205b8358978fa from: Jelmer Vernooij date: Thu Jun 16 17:16:59 2022 UTC Fix reading of chunks in server. Fixes #977 commit - ac37905a9197f102534a0ef0cb4946bd16e522bd commit + 31490d6b2395abd4459f794863b205b8358978fa blob - f761ccaef857b5dcc52bd6eabe193896b779b523 blob + ffb09bf2e31af7558226378fc160a1243da68c67 --- NEWS +++ NEWS @@ -1,4 +1,6 @@ 0.20.44 UNRELEASED + + * Fix reading of chunks in server. (Jelmer Vernooij, #977) 0.20.43 2022-06-07 blob - d5dc9f04bc8d077f282f9bd2fb319c20253c043e blob + 6ed9cac2c3b9e595b3eba070fd0ccef979c56148 --- dulwich/tests/test_porcelain.py +++ dulwich/tests/test_porcelain.py @@ -33,7 +33,7 @@ import tarfile import tempfile import threading import time -from unittest import skipIf, expectedFailure +from unittest import skipIf from dulwich import porcelain from dulwich.diff_tree import tree_changes @@ -2909,8 +2909,6 @@ class ServerTests(PorcelainTestCase): with self._serving() as url: porcelain.pull(self.repo, url, "master") - # TODO: See https://github.com/jelmer/dulwich/issues/977 - @expectedFailure def test_push(self): c1, = build_commit_graph(self.repo.object_store, [[1]]) self.repo.refs[b"refs/heads/master"] = c1.id blob - 27ac8577ad6eb73a7fb204437a432ad9c37402e9 blob + daa728944f853c304a7de8e628b34f70b1c6f4fa --- dulwich/web.py +++ dulwich/web.py @@ -237,6 +237,34 @@ def get_info_packs(req, backend, mat): req.respond(HTTP_OK, "text/plain") logger.info("Emulating dumb info/packs") return generate_objects_info_packs(get_repo(backend, mat)) + + +def _chunk_iter(f): + while True: + line = f.readline() + length = int(line.rstrip(), 16) + chunk = f.read(length + 2) + if length == 0: + break + yield chunk[:-2] + + +class ChunkReader(object): + + def __init__(self, f): + self._iter = _chunk_iter(f) + self._buffer = [] + + def read(self, n): + while sum(map(len, self._buffer)) < n: + try: + self._buffer.append(next(self._iter)) + except StopIteration: + break + f = b''.join(self._buffer) + ret = f[:n] + self._buffer = [f[n:]] + return ret class _LengthLimitedFile(object): @@ -276,7 +304,11 @@ def handle_service_request(req, backend, mat): return req.nocache() write = req.respond(HTTP_OK, "application/x-%s-result" % service) - proto = ReceivableProtocol(req.environ["wsgi.input"].read, write) + if req.environ.get('HTTP_TRANSFER_ENCODING') == 'chunked': + read = ChunkReader(req.environ["wsgi.input"]).read + else: + read = req.environ["wsgi.input"].read + proto = ReceivableProtocol(read, write) # TODO(jelmer): Find a way to pass in repo, rather than having handler_cls # reopen. handler = handler_cls(backend, [url_prefix(mat)], proto, stateless_rpc=req)