From fe9bf84378815e995880f4515dc6907eb71de13a Mon Sep 17 00:00:00 2001 From: Jonas Haag Date: Tue, 12 Apr 2016 11:16:44 +0200 Subject: [PATCH] Don't expect 'wsgi.input' to have working 'seek' method This is a follow-up to 5a69c46 which misses the fact that even though an input stream might have 'seek' and 'tell' methods, they do not necessarily have to be implemented. See also http://bugs.python.org/issue12877 --- dulwich/tests/test_web.py | 46 ++++++++++++++++++++++++++++----------- dulwich/web.py | 11 +++++----- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/dulwich/tests/test_web.py b/dulwich/tests/test_web.py index 9f040b49e..6467b4049 100644 --- a/dulwich/tests/test_web.py +++ b/dulwich/tests/test_web.py @@ -64,6 +64,30 @@ ) +class MinimalistWSGIInputStream(object): + """WSGI input stream with no 'seek()' and 'tell()' methods.""" + def __init__(self, data): + self.data = data + self.pos = 0 + + def read(self, howmuch): + start = self.pos + end = self.pos + howmuch + if start >= len(self.data): + return '' + self.pos = end + return self.data[start:end] + + +class MinimalistWSGIInputStream2(MinimalistWSGIInputStream): + """WSGI input stream with no *working* 'seek()' and 'tell()' methods.""" + def seek(self, pos): + raise NotImplementedError + + def tell(self): + raise NotImplementedError + + class TestHTTPGitRequest(HTTPGitRequest): """HTTPGitRequest with overridden methods to help test caching.""" @@ -497,19 +521,15 @@ def test_call_no_seek(self): 'wsgi.input' except for '.read()'. (In particular, it shouldn't require '.seek()'. See https://github.com/jelmer/dulwich/issues/140.) """ - class MinimalistWSGIInputStream(object): - def __init__(self, data): - self.data = data - self.pos = 0 - - def read(self, howmuch): - start = self.pos - end = self.pos + howmuch - if start >= len(self.data): - return '' - self.pos = end - return self.data[start:end] - zstream, zlength = self._get_zstream(self.example_text) self._test_call(self.example_text, MinimalistWSGIInputStream(zstream.read()), zlength) + + def test_call_no_working_seek(self): + """ + Similar to 'test_call_no_seek', but this time the methods are available + (but defunct). See https://github.com/jonashaag/klaus/issues/154. + """ + zstream, zlength = self._get_zstream(self.example_text) + self._test_call(self.example_text, + MinimalistWSGIInputStream2(zstream.read()), zlength) diff --git a/dulwich/web.py b/dulwich/web.py index a4fa941fc..89b1e8615 100644 --- a/dulwich/web.py +++ b/dulwich/web.py @@ -371,13 +371,14 @@ def __init__(self, application): def __call__(self, environ, start_response): if environ.get('HTTP_CONTENT_ENCODING', '') == 'gzip': - if hasattr(environ['wsgi.input'], 'seek'): + try: + environ['wsgi.input'].tell() wsgi_input = environ['wsgi.input'] - else: + except (AttributeError, IOError, NotImplementedError): # The gzip implementation in the standard library of Python 2.x - # requires the '.seek()' and '.tell()' methods to be available - # on the input stream. Read the data into a temporary file to - # work around this limitation. + # requires working '.seek()' and '.tell()' methods on the input + # stream. Read the data into a temporary file to work around + # this limitation. wsgi_input = tempfile.SpooledTemporaryFile(16 * 1024 * 1024) shutil.copyfileobj(environ['wsgi.input'], wsgi_input) wsgi_input.seek(0)