Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address issue #197 re: handshake customization docs. #199

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,42 @@ Server

.. automethod:: handshake(origins=None, subprotocols=None, extra_headers=None)
.. automethod:: select_subprotocol(client_protos, server_protos)
.. automethod:: get_response_status()
.. automethod:: get_response_status(set_header)

.. _custom-handling:

Customizing Request Handling
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To set additional response headers or to selectively bypass the handshake,
you can subclass :class:`~websockets.server.WebSocketServerProtocol`,
override the
:meth:`~websockets.server.WebSocketServerProtocol.get_response_status`
method, and pass the class to :func:`~websockets.server.serve()` via the
``create_protocol`` keyword argument.

If :meth:`~websockets.server.WebSocketServerProtocol.get_response_status`
returns a status code other than the default of
``HTTPStatus.SWITCHING_PROTOCOLS``, the
:class:`~websockets.server.WebSocketServerProtocol` object will close the
connection immediately and respond with that status code.

For example, the request headers can be examined and the request
authenticated to decide whether to return ``HTTPStatus.UNAUTHORIZED`` or
``HTTPStatus.FORBIDDEN``. Similarly, the current request path can be
examined to check for ``HTTPStatus.NOT_FOUND``.

The following instance attributes are guaranteed to be available from
within this method:

* ``origin``
* ``path``
* ``raw_request_headers``
* ``request_headers``

The ``set_header(key, value)`` function, which is provided as an argument to
``get_response_status()``, can be used to set additional response headers,
regardless of whether the handshake is aborted.

Client
......
Expand Down
2 changes: 1 addition & 1 deletion docs/cheatsheet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Server
execute the application logic, and finally closes the connection after
the handler exits normally or with an exception.

* For advanced customization, you may subclass
* For :ref:`advanced customization <custom-handling>`, you may subclass
:class:`~websockets.server.WebSocketServerProtocol` and pass either this
subclass or a factory function as the ``create_protocol`` argument.

Expand Down
23 changes: 12 additions & 11 deletions websockets/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,26 +218,26 @@ def select_subprotocol(client_protos, server_protos):
priority = lambda p: client_protos.index(p) + server_protos.index(p)
return sorted(common_protos, key=priority)[0]

# This method is declared as a coroutine because overridden versions can
# require network requests, for example (e.g. for authentication checks).
@asyncio.coroutine
def get_response_status(self, set_header):
"""
Return a :class:`~http.HTTPStatus` for the HTTP response.
Return an :class:`~http.HTTPStatus` member for the HTTP response.

(:class:`~http.HTTPStatus` was added in Python 3.5. On earlier
versions, a compatible object must be returned. Check the definition
of ``SWITCHING_PROTOCOLS`` for an example.)

This method may be overridden to check the request headers and set a
different status, for example to authenticate the request and return
``HTTPStatus.UNAUTHORIZED`` or ``HTTPStatus.FORBIDDEN``.
The ``set_header`` argument is a function accepting a header name
and value.

It is declared as a coroutine because such authentication checks are
likely to require network requests.
The following instance attributes should be set prior to calling
this method: ``origin``, ``path``, ``raw_request_headers``, and
``request_headers``.

The connection is closed immediately after sending the response when
the status code is not ``HTTPStatus.SWITCHING_PROTOCOLS``.

Call ``set_header(key, value)`` to set additional response headers.
This method may be overridden to interrupt the handshake and respond
with a different status.

"""
return SWITCHING_PROTOCOLS
Expand All @@ -260,7 +260,8 @@ def handshake(self, origins=None, subprotocols=None, extra_headers=None):
Raise :exc:`~websockets.exceptions.InvalidHandshake` or a subclass if
the handshake fails.

Return the URI of the request.
Return the URI of the request, or ``None`` if the handshake was
aborted.

"""
path, headers = yield from self.read_http_request()
Expand Down