dulwich-users team mailing list archive
-
dulwich-users team
-
Mailing list archive
-
Message #00144
[PATCH 3/9] web: Use write() callable for output.
From: Dave Borowitz <dborowitz@xxxxxxxxxx>
PEP 333 specifies that start_response must return a write() callable
for compatibility with legacy stream-based APIs, which includes the
tunneled git protocol code.
Change-Id: I1982bc690d5cbddf962bd6660791111352338dd5
---
NEWS | 3 +++
dulwich/tests/test_web.py | 17 +++++++++++++----
dulwich/web.py | 14 +++++---------
3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/NEWS b/NEWS
index c710b83..ec32c5f 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@
* Use slots for core objects to save up on memory. (Jelmer Vernooij)
+ * Web server supports streaming progress/pack output. (Dave Borowitz)
+
+
0.6.1 2010-07-22
BUG FIXES
diff --git a/dulwich/tests/test_web.py b/dulwich/tests/test_web.py
index 6a2f7c1..9e5010a 100644
--- a/dulwich/tests/test_web.py
+++ b/dulwich/tests/test_web.py
@@ -50,10 +50,12 @@ class WebTestCase(TestCase):
handlers=self._handlers())
self._status = None
self._headers = []
+ self._output = StringIO()
def _start_response(self, status, headers):
self._status = status
self._headers = list(headers)
+ return self._output.write
def _handlers(self):
return None
@@ -197,8 +199,12 @@ class SmartHandlersTestCase(WebTestCase):
if content_length is not None:
self._environ['CONTENT_LENGTH'] = content_length
mat = re.search('.*', '/git-upload-pack')
- output = ''.join(handle_service_request(self._req, 'backend', mat))
- self.assertEqual('handled input: foo', output)
+ handler_output = ''.join(
+ handle_service_request(self._req, 'backend', mat))
+ write_output = self._output.getvalue()
+ # Ensure all output was written via the write callback.
+ self.assertEqual('', handler_output)
+ self.assertEqual('handled input: foo', write_output)
response_type = 'application/x-git-upload-pack-response'
self.assertTrue(('Content-Type', response_type) in self._headers)
self.assertFalse(self._handler.advertise_refs)
@@ -223,11 +229,14 @@ class SmartHandlersTestCase(WebTestCase):
self._environ['QUERY_STRING'] = 'service=git-upload-pack'
mat = re.search('.*', '/git-upload-pack')
- output = ''.join(get_info_refs(self._req, 'backend', mat))
+ handler_output = ''.join(get_info_refs(self._req, 'backend', mat))
+ write_output = self._output.getvalue()
self.assertEquals(('001e# service=git-upload-pack\n'
'0000'
# input is ignored by the handler
- 'handled input: '), output)
+ 'handled input: '), write_output)
+ # Ensure all output was written via the write callback.
+ self.assertEquals('', handler_output)
self.assertTrue(self._handler.advertise_refs)
self.assertTrue(self._handler.stateless_rpc)
diff --git a/dulwich/web.py b/dulwich/web.py
index d7ac60b..d42bd6a 100644
--- a/dulwich/web.py
+++ b/dulwich/web.py
@@ -159,15 +159,13 @@ def get_info_refs(req, backend, mat):
yield req.forbidden('Unsupported service %s' % service)
return
req.nocache()
- req.respond(HTTP_OK, 'application/x-%s-advertisement' % service)
- output = StringIO()
- proto = ReceivableProtocol(StringIO().read, output.write)
+ write = req.respond(HTTP_OK, 'application/x-%s-advertisement' % service)
+ proto = ReceivableProtocol(StringIO().read, write)
handler = handler_cls(backend, [url_prefix(mat)], proto,
stateless_rpc=True, advertise_refs=True)
handler.proto.write_pkt_line('# service=%s\n' % service)
handler.proto.write_pkt_line(None)
handler.handle()
- yield output.getvalue()
else:
# non-smart fallback
# TODO: select_getanyfile() (see http-backend.c)
@@ -230,9 +228,8 @@ def handle_service_request(req, backend, mat):
yield req.forbidden('Unsupported service %s' % service)
return
req.nocache()
- req.respond(HTTP_OK, 'application/x-%s-response' % service)
+ write = req.respond(HTTP_OK, 'application/x-%s-response' % service)
- output = StringIO()
input = req.environ['wsgi.input']
# This is not necessary if this app is run from a conforming WSGI server.
# Unfortunately, there's no way to tell that at this point.
@@ -241,10 +238,9 @@ def handle_service_request(req, backend, mat):
content_length = req.environ.get('CONTENT_LENGTH', '')
if content_length:
input = _LengthLimitedFile(input, int(content_length))
- proto = ReceivableProtocol(input.read, output.write)
+ proto = ReceivableProtocol(input.read, write)
handler = handler_cls(backend, [url_prefix(mat)], proto, stateless_rpc=True)
handler.handle()
- yield output.getvalue()
class HTTPGitRequest(object):
@@ -273,7 +269,7 @@ class HTTPGitRequest(object):
self._headers.append(('Content-Type', content_type))
self._headers.extend(self._cache_headers)
- self._start_response(status, self._headers)
+ return self._start_response(status, self._headers)
def not_found(self, message):
"""Begin a HTTP 404 response and return the text of a message."""
--
1.7.1
References