Handle errors in synchronous middleware

If synchronous middleware throws an exception,
- catch the exception
- emit an 'error' event
- call the latest 'done' callback to unwind the middleware stack

Async middleware is still responsible for performing these steps after
it yields to the event loop.