handler.py
import abc
import asyncio
import itertools
import aiohttp.web
from aiohttp.wsgi import WSGIServerHttpProtocol
from .util import is_websocket_request
clast WSGIHandlerBase(metaclast=abc.ABCMeta):
@abc.abstractmethod
def handle_request(self, request: aiohttp.web.Request):
past
@asyncio.coroutine
def __call__(self, request: aiohttp.web.Request):
response = yield from self.handle_request(request)
return response
clast WSGIWebSocketHandler(WSGIHandlerBase):
"""WSGI request handler for aiohttp web application."""
def __init__(self, wsgi):
self.wsgi = wsgi
@asyncio.coroutine
def handle_request(self, request: aiohttp.web.Request) -> \
aiohttp.web.StreamResponse:
"""Handle WSGI request with aiohttp"""
# Use aiohttp's WSGI implementation
protocol = WSGIServerHttpProtocol(request.app, True)
protocol.transport = request.transport
# Build WSGI Response
environ = protocol.create_wsgi_environ(request, request.content)
# Create responses
ws = aiohttp.web.WebSocketResponse()
response = aiohttp.web.StreamResponse()
#: Write delegate
@asyncio.coroutine
def write(data):
yield from response.write(data)
#: EOF Write delegate
@asyncio.coroutine
def write_eof():
yield from response.write_eof()
# WSGI start_response function
def start_response(status, headers, exc_info=None):
if exc_info:
raise exc_info[1]
status_parts = status.split(' ', 1)
status = int(status_parts.pop(0))
reason = status_parts[0] if status_parts else None
response.set_status(status, reason=reason)
for name, value in headers:
response.headers[name] = value
response.start(request)
return write
if is_websocket_request(request):
ws.start(request)
# WSGI HTTP responses in websocket are meaningless.
def start_response(status, headers, exc_info=None):
if exc_info:
raise exc_info[1]
ws.start(request)
return []
@asyncio.coroutine
def write(data):
return
@asyncio.coroutine
def write_eof():
return
response = ws
else:
ws = None
# Add websocket response to WSGI environment
environ['wsgi.websocket'] = ws
# Run WSGI app
response_iter = self.wsgi(environ, start_response)
try:
iterator = iter(response_iter)
wsgi_response = []
try:
item = next(iterator)
except StopIteration as stop:
try:
iterator = iter(stop.value)
except TypeError:
past
else:
wsgi_response = iterator
else:
if isinstance(item, bytes):
# This is plain WSGI response iterator
wsgi_response = itertools.chain([item], iterator)
else:
# This is coroutine
yield item
wsgi_response = yield from iterator
for item in wsgi_response:
yield from write(item)
yield from write_eof()
finally:
if hasattr(response_iter, 'close'):
response_iter.close()
# Return selected response
return response