diff --git a/examples/exc.py b/examples/exc.py
index c02ee0b..c6994aa 100644
--- a/examples/exc.py
+++ b/examples/exc.py
@@ -1,4 +1,12 @@
+from httpout import run
+
+
print('Hi')
-raise ValueError
+
+async def main():
+ raise ValueError
+
+
+run(main())
diff --git a/httpout/httpout.py b/httpout/httpout.py
index 42b24e9..4f78d8b 100644
--- a/httpout/httpout.py
+++ b/httpout/httpout.py
@@ -5,7 +5,6 @@
import os
import sys
-from traceback import TracebackException
from types import ModuleType
from awaiter import MultiThreadExecutor
@@ -277,32 +276,7 @@ async def _on_request(self, **server):
ctx.module_path = module_path
except BaseException as exc:
await server['response'].join()
-
- if not response.headers_sent():
- response.set_status(500, b'Internal Server Error')
- response.set_content_type(b'text/html; charset=utf-8')
- request.http_keepalive = False
-
- if isinstance(exc, Exception):
- if request.protocol.options['debug']:
- te = TracebackException.from_exception(exc)
- await response.write(
- b'
\n' % b''.join(
- html_escape(line)
- .encode() for line in te.format()
- )
- )
- else:
- await response.write(
- f'- {exc.__class__.__name__}: '
- f'{html_escape(str(exc))}
\n'
- .encode()
- )
- elif isinstance(exc, SystemExit):
- if exc.code:
- await response.write(str(exc.code).encode())
- else:
- request.protocol.print_exception(exc)
+ await server['response'].handle_exception(exc)
finally:
await g.executor.submit(
cleanup_modules, server['modules'], excludes
diff --git a/httpout/lib/http_response.py b/httpout/lib/http_response.py
index 7efe514..b6b29df 100644
--- a/httpout/lib/http_response.py
+++ b/httpout/lib/http_response.py
@@ -3,6 +3,9 @@
import asyncio
import concurrent.futures
+from traceback import TracebackException
+from tremolo.utils import html_escape
+
class HTTPResponse:
def __init__(self, response):
@@ -24,6 +27,33 @@ async def join(self):
while self.tasks:
await self.tasks.pop()
+ async def handle_exception(self, exc):
+ if not self.response.headers_sent():
+ self.response.set_status(500, b'Internal Server Error')
+ self.response.set_content_type(b'text/html; charset=utf-8')
+ self.response.request.http_keepalive = False
+
+ if isinstance(exc, Exception):
+ if self.response.request.protocol.options['debug']:
+ te = TracebackException.from_exception(exc)
+ await self.response.write(
+ b'\n' % b''.join(
+ html_escape(line)
+ .encode() for line in te.format()
+ )
+ )
+ else:
+ await self.response.write(
+ f'- {exc.__class__.__name__}: '
+ f'{html_escape(str(exc))}
\n'
+ .encode()
+ )
+ elif isinstance(exc, SystemExit):
+ if exc.code:
+ await self.response.write(str(exc.code).encode())
+ else:
+ self.response.request.protocol.print_exception(exc)
+
def run_coroutine(self, coro):
fut = concurrent.futures.Future()
@@ -35,7 +65,9 @@ async def callback():
fut.set_result(result)
except BaseException as exc:
if not fut.done():
- fut.set_exception(exc)
+ fut.set_result(None)
+
+ await self.handle_exception(exc)
self.loop.call_soon_threadsafe(self.create_task, callback())
return fut