To support altering headers before responses are sent, among other things, there should be a signals framework so people can hook into the response process. This would be extensible for other uses too. This issue follows on from #393.
The proposal is:
Create a new signals module, containing a Signal class. Its constructor takes a single argument, arguments, saying which arguments must be passed when dispatching the signal. This class has a method for checking that potential callbacks have a compatible signature. The module also contains instances of this class for individual types of signal (e.g. response_start = Signal({'request', 'response'}) — I can't yet think of what other signals might be useful).
Application gets a new _signals = defaultdict(list) and a @property that exposes a view of it. It gets a add_signal_callback(signal : Signal, callback : Callable) method, which checks that the callback is compatible (see above) and coerces the calback to a coroutine, before appending the callback to self._signals[signal].
Signal dispatching is done by Appllication.dispatch_signal(signal : Signal, kwargs : dict), which iterates through the registered signals, calling each in turn.
Response.start() is modified to dispatch the response_start signal after this line.
I don't think there's any need to create signals for the request creation phase, as the request can be modified safely with middleware.
The use-case of adding response headers from middleware becomes this slightly contrived example:
import asyncio
import time
from aiohttp.signals import response_start
@asyncio.coroutine
def add_header_middleware(app, handler):
@asyncio.coroutine
def middleware(request):
request.started = time.time()
return (yield from handler(request))
return middleware
def add_request_started(*, request, response):
response.headers['X-Started'] = str(request.started)
app = Application(middlewares=(add_header_middleware,))
app.add_signal_handler(response_start, add_request_started)
To support altering headers before responses are sent, among other things, there should be a signals framework so people can hook into the response process. This would be extensible for other uses too. This issue follows on from #393.
The proposal is:
Create a new
signalsmodule, containing aSignalclass. Its constructor takes a single argument,arguments, saying which arguments must be passed when dispatching the signal. This class has a method for checking that potential callbacks have a compatible signature. The module also contains instances of this class for individual types of signal (e.g.response_start = Signal({'request', 'response'})— I can't yet think of what other signals might be useful).Applicationgets a new_signals = defaultdict(list)and a@propertythat exposes a view of it. It gets aadd_signal_callback(signal : Signal, callback : Callable)method, which checks that the callback is compatible (see above) and coerces the calback to a coroutine, before appending the callback toself._signals[signal].Signal dispatching is done by
Appllication.dispatch_signal(signal : Signal, kwargs : dict), which iterates through the registered signals, calling each in turn.Response.start()is modified to dispatch theresponse_startsignal after this line.I don't think there's any need to create signals for the request creation phase, as the request can be modified safely with middleware.
The use-case of adding response headers from middleware becomes this slightly contrived example: