commit
4ccc782e29
|
@ -59,6 +59,7 @@ if __name__ == "__main__":
|
|||
* [Class Based Views](docs/class_based_views.md)
|
||||
* [Cookies](docs/cookies.md)
|
||||
* [Static Files](docs/static_files.md)
|
||||
* [Custom Protocol](docs/custom_protocol.md)
|
||||
* [Testing](docs/testing.md)
|
||||
* [Deploying](docs/deploying.md)
|
||||
* [Contributing](docs/contributing.md)
|
||||
|
|
70
docs/custom_protocol.md
Normal file
70
docs/custom_protocol.md
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Custom Protocol
|
||||
|
||||
You can change the behavior of protocol by using custom protocol.
|
||||
If you want to use custom protocol, you should put subclass of [protocol class](https://docs.python.org/3/library/asyncio-protocol.html#protocol-classes) in the protocol keyword argument of `sanic.run()`. The constructor of custom protocol class gets following keyword arguments from Sanic.
|
||||
|
||||
* loop
|
||||
`loop` is an asyncio compatible event loop.
|
||||
|
||||
* connections
|
||||
`connections` is a `set object` to store protocol objects.
|
||||
When Sanic receives `SIGINT` or `SIGTERM`, Sanic executes `protocol.close_if_idle()` for a `protocol objects` stored in connections.
|
||||
|
||||
* signal
|
||||
`signal` is a `sanic.server.Signal object` with `stopped attribute`.
|
||||
When Sanic receives `SIGINT` or `SIGTERM`, `signal.stopped` becomes `True`.
|
||||
|
||||
* request_handler
|
||||
`request_handler` is a coroutine that takes a `sanic.request.Request` object and a `response callback` as arguments.
|
||||
|
||||
* error_handler
|
||||
`error_handler` is a `sanic.exceptions.Handler` object.
|
||||
|
||||
* request_timeout
|
||||
`request_timeout` is seconds for timeout.
|
||||
|
||||
* request_max_size
|
||||
`request_max_size` is bytes of max request size.
|
||||
|
||||
## Example
|
||||
By default protocol, an error occurs, if the handler does not return an `HTTPResponse object`.
|
||||
In this example, By rewriting `write_response()`, if the handler returns `str`, it will be converted to an `HTTPResponse object`.
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.server import HttpProtocol
|
||||
from sanic.response import text
|
||||
|
||||
app = Sanic(__name__)
|
||||
|
||||
|
||||
class CustomHttpProtocol(HttpProtocol):
|
||||
|
||||
def __init__(self, *, loop, request_handler, error_handler,
|
||||
signal, connections, request_timeout, request_max_size):
|
||||
super().__init__(
|
||||
loop=loop, request_handler=request_handler,
|
||||
error_handler=error_handler, signal=signal,
|
||||
connections=connections, request_timeout=request_timeout,
|
||||
request_max_size=request_max_size)
|
||||
|
||||
def write_response(self, response):
|
||||
if isinstance(response, str):
|
||||
response = text(response)
|
||||
self.transport.write(
|
||||
response.output(self.request.version)
|
||||
)
|
||||
self.transport.close()
|
||||
|
||||
|
||||
@app.route('/')
|
||||
async def string(request):
|
||||
return 'string'
|
||||
|
||||
|
||||
@app.route('/1')
|
||||
async def response(request):
|
||||
return text('response')
|
||||
|
||||
app.run(host='0.0.0.0', port=8000, protocol=CustomHttpProtocol)
|
||||
```
|
|
@ -13,7 +13,7 @@ from .exceptions import Handler
|
|||
from .log import log
|
||||
from .response import HTTPResponse
|
||||
from .router import Router
|
||||
from .server import serve
|
||||
from .server import serve, HttpProtocol
|
||||
from .static import register as static_register
|
||||
from .exceptions import ServerError
|
||||
|
||||
|
@ -242,7 +242,7 @@ class Sanic:
|
|||
|
||||
def run(self, host="127.0.0.1", port=8000, debug=False, before_start=None,
|
||||
after_start=None, before_stop=None, after_stop=None, sock=None,
|
||||
workers=1, loop=None):
|
||||
workers=1, loop=None, protocol=HttpProtocol):
|
||||
"""
|
||||
Runs the HTTP Server and listens until keyboard interrupt or term
|
||||
signal. On termination, drains connections before closing.
|
||||
|
@ -261,6 +261,7 @@ class Sanic:
|
|||
:param workers: Number of processes
|
||||
received before it is respected
|
||||
:param loop: asyncio compatible event loop
|
||||
:param protocol: Subclass of asyncio protocol class
|
||||
:return: Nothing
|
||||
"""
|
||||
self.error_handler.debug = True
|
||||
|
@ -268,6 +269,7 @@ class Sanic:
|
|||
self.loop = loop
|
||||
|
||||
server_settings = {
|
||||
'protocol': protocol,
|
||||
'host': host,
|
||||
'port': port,
|
||||
'sock': sock,
|
||||
|
|
|
@ -224,24 +224,30 @@ def trigger_events(events, loop):
|
|||
|
||||
|
||||
def serve(host, port, request_handler, error_handler, before_start=None,
|
||||
after_start=None, before_stop=None, after_stop=None,
|
||||
debug=False, request_timeout=60, sock=None,
|
||||
request_max_size=None, reuse_port=False, loop=None):
|
||||
after_start=None, before_stop=None, after_stop=None, debug=False,
|
||||
request_timeout=60, sock=None, request_max_size=None,
|
||||
reuse_port=False, loop=None, protocol=HttpProtocol):
|
||||
"""
|
||||
Starts asynchronous HTTP Server on an individual process.
|
||||
:param host: Address to host on
|
||||
:param port: Port to host on
|
||||
:param request_handler: Sanic request handler with middleware
|
||||
:param error_handler: Sanic error handler with middleware
|
||||
:param before_start: Function to be executed before the server starts
|
||||
listening. Takes single argument `loop`
|
||||
:param after_start: Function to be executed after the server starts
|
||||
listening. Takes single argument `loop`
|
||||
:param before_stop: Function to be executed when a stop signal is
|
||||
received before it is respected. Takes single argumenet `loop`
|
||||
:param after_stop: Function to be executed when a stop signal is
|
||||
received after it is respected. Takes single argumenet `loop`
|
||||
:param debug: Enables debug output (slows server)
|
||||
:param request_timeout: time in seconds
|
||||
:param sock: Socket for the server to accept connections from
|
||||
:param request_max_size: size in bytes, `None` for no limit
|
||||
:param reuse_port: `True` for multiple workers
|
||||
:param loop: asyncio compatible event loop
|
||||
:param protocol: Subclass of asyncio protocol class
|
||||
:return: Nothing
|
||||
"""
|
||||
loop = loop or async_loop.new_event_loop()
|
||||
|
@ -255,7 +261,7 @@ def serve(host, port, request_handler, error_handler, before_start=None,
|
|||
connections = set()
|
||||
signal = Signal()
|
||||
server = partial(
|
||||
HttpProtocol,
|
||||
protocol,
|
||||
loop=loop,
|
||||
connections=connections,
|
||||
signal=signal,
|
||||
|
|
|
@ -16,8 +16,8 @@ async def local_request(method, uri, cookies=None, *args, **kwargs):
|
|||
|
||||
|
||||
def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
|
||||
loop=None, debug=False, *request_args,
|
||||
**request_kwargs):
|
||||
loop=None, debug=False, server_kwargs={},
|
||||
*request_args, **request_kwargs):
|
||||
results = []
|
||||
exceptions = []
|
||||
|
||||
|
@ -36,7 +36,7 @@ def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
|
|||
app.stop()
|
||||
|
||||
app.run(host=HOST, debug=debug, port=42101,
|
||||
after_start=_collect_response, loop=loop)
|
||||
after_start=_collect_response, loop=loop, **server_kwargs)
|
||||
|
||||
if exceptions:
|
||||
raise ValueError("Exception during request: {}".format(exceptions))
|
||||
|
|
32
tests/test_custom_protocol.py
Normal file
32
tests/test_custom_protocol.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from sanic import Sanic
|
||||
from sanic.server import HttpProtocol
|
||||
from sanic.response import text
|
||||
from sanic.utils import sanic_endpoint_test
|
||||
|
||||
app = Sanic('test_custom_porotocol')
|
||||
|
||||
|
||||
class CustomHttpProtocol(HttpProtocol):
|
||||
|
||||
def write_response(self, response):
|
||||
if isinstance(response, str):
|
||||
response = text(response)
|
||||
self.transport.write(
|
||||
response.output(self.request.version)
|
||||
)
|
||||
self.transport.close()
|
||||
|
||||
|
||||
@app.route('/1')
|
||||
async def handler_1(request):
|
||||
return 'OK'
|
||||
|
||||
|
||||
def test_use_custom_protocol():
|
||||
server_kwargs = {
|
||||
'protocol': CustomHttpProtocol
|
||||
}
|
||||
request, response = sanic_endpoint_test(app, uri='/1',
|
||||
server_kwargs=server_kwargs)
|
||||
assert response.status == 200
|
||||
assert response.text == 'OK'
|
Loading…
Reference in New Issue
Block a user