Support responses with more than one cookie in WSGI and ASGI extensions

This commit is contained in:
Miguel Grinberg
2022-08-04 11:20:05 +01:00
parent c9e148bd04
commit e8d16cf3f9
4 changed files with 41 additions and 11 deletions

View File

@@ -89,10 +89,17 @@ class Microdot(BaseMicrodot):
res = await self.dispatch_request(req) res = await self.dispatch_request(req)
res.complete() res.complete()
header_list = []
for name, value in res.headers.items():
if not isinstance(value, list):
header_list.append((name, value))
else:
for v in value:
header_list.append((name, v))
await send({'type': 'http.response.start', await send({'type': 'http.response.start',
'status': res.status_code, 'status': res.status_code,
'headers': [(name, value) 'headers': header_list})
for name, value in res.headers.items()]})
cancelled = False cancelled = False

View File

@@ -34,9 +34,14 @@ class Microdot(BaseMicrodot):
res.complete() res.complete()
reason = res.reason or ('OK' if res.status_code == 200 else 'N/A') reason = res.reason or ('OK' if res.status_code == 200 else 'N/A')
start_response( header_list = []
str(res.status_code) + ' ' + reason, for name, value in res.headers.items():
[(name, value) for name, value in res.headers.items()]) if not isinstance(value, list):
header_list.append((name, value))
else:
for v in value:
header_list.append((name, v))
start_response(str(res.status_code) + ' ' + reason, header_list)
return res.body_iter() return res.body_iter()
def __call__(self, environ, start_response): def __call__(self, environ, start_response):

View File

@@ -44,6 +44,11 @@ class TestMicrodotASGI(unittest.TestCase):
return Response(body=R(), headers={'Content-Length': '8'}) return Response(body=R(), headers={'Content-Length': '8'})
@app.after_request
def after_request(req, res):
res.set_cookie('foo', 'foo')
res.set_cookie('bar', 'bar', http_only=True)
scope = { scope = {
'type': 'http', 'type': 'http',
'path': '/foo/bar', 'path': '/foo/bar',
@@ -77,9 +82,13 @@ class TestMicrodotASGI(unittest.TestCase):
async def send(packet): async def send(packet):
if packet['type'] == 'http.response.start': if packet['type'] == 'http.response.start':
self.assertEqual(packet['status'], 200) self.assertEqual(packet['status'], 200)
self.assertEqual( expected_headers = [('Content-Length', '8'),
packet['headers'], ('Content-Type', 'text/plain'),
[('Content-Length', '8'), ('Content-Type', 'text/plain')]) ('Set-Cookie', 'foo=foo'),
('Set-Cookie', 'bar=bar; HttpOnly')]
self.assertEqual(len(packet['headers']), len(expected_headers))
for header in expected_headers:
self.assertIn(header, packet['headers'])
elif packet['type'] == 'http.response.body': elif packet['type'] == 'http.response.body':
self.assertIn(packet['body'], self.assertIn(packet['body'],
[b're', b'sp', b'on', b'se', b'']) [b're', b'sp', b'on', b'se', b''])

View File

@@ -32,6 +32,11 @@ class TestMicrodotWSGI(unittest.TestCase):
self.assertEqual(req.body, b'body') self.assertEqual(req.body, b'body')
return 'response' return 'response'
@app.after_request
def after_request(req, resp):
resp.set_cookie('foo', 'foo')
resp.set_cookie('bar', 'bar', http_only=True)
environ = { environ = {
'SCRIPT_NAME': '/foo', 'SCRIPT_NAME': '/foo',
'PATH_INFO': '/bar', 'PATH_INFO': '/bar',
@@ -48,9 +53,13 @@ class TestMicrodotWSGI(unittest.TestCase):
def start_response(status, headers): def start_response(status, headers):
self.assertEqual(status, '200 OK') self.assertEqual(status, '200 OK')
self.assertEqual( expected_headers = [('Content-Length', '8'),
headers, ('Content-Type', 'text/plain'),
[('Content-Length', '8'), ('Content-Type', 'text/plain')]) ('Set-Cookie', 'foo=foo'),
('Set-Cookie', 'bar=bar; HttpOnly')]
self.assertEqual(len(headers), len(expected_headers))
for header in expected_headers:
self.assertIn(header, headers)
r = app(environ, start_response) r = app(environ, start_response)
self.assertEqual(next(r), b'response') self.assertEqual(next(r), b'response')