tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sansio.rst (11235B)


      1 Integrate the Sans-I/O layer
      2 ============================
      3 
      4 .. currentmodule:: websockets
      5 
      6 This guide explains how to integrate the `Sans-I/O`_ layer of websockets to
      7 add support for WebSocket in another library.
      8 
      9 .. _Sans-I/O: https://sans-io.readthedocs.io/
     10 
     11 As a prerequisite, you should decide how you will handle network I/O and
     12 asynchronous control flow.
     13 
     14 Your integration layer will provide an API for the application on one side,
     15 will talk to the network on the other side, and will rely on websockets to
     16 implement the protocol in the middle.
     17 
     18 .. image:: ../topics/data-flow.svg
     19   :align: center
     20 
     21 Opening a connection
     22 --------------------
     23 
     24 Client-side
     25 ...........
     26 
     27 If you're building a client, parse the URI you'd like to connect to::
     28 
     29    from websockets.uri import parse_uri
     30 
     31    wsuri = parse_uri("ws://example.com/")
     32 
     33 Open a TCP connection to ``(wsuri.host, wsuri.port)`` and perform a TLS
     34 handshake if ``wsuri.secure`` is :obj:`True`.
     35 
     36 Initialize a :class:`~client.ClientProtocol`::
     37 
     38    from websockets.client import ClientProtocol
     39 
     40    protocol = ClientProtocol(wsuri)
     41 
     42 Create a WebSocket handshake request
     43 with :meth:`~client.ClientProtocol.connect` and send it
     44 with :meth:`~client.ClientProtocol.send_request`::
     45 
     46    request = protocol.connect()
     47    protocol.send_request(request)
     48 
     49 Then, call :meth:`~protocol.Protocol.data_to_send` and send its output to
     50 the network, as described in `Send data`_ below.
     51 
     52 Once you receive enough data, as explained in `Receive data`_ below, the first
     53 event returned by :meth:`~protocol.Protocol.events_received` is the WebSocket
     54 handshake response.
     55 
     56 When the handshake fails, the reason is available in
     57 :attr:`~client.ClientProtocol.handshake_exc`::
     58 
     59    if protocol.handshake_exc is not None:
     60        raise protocol.handshake_exc
     61 
     62 Else, the WebSocket connection is open.
     63 
     64 A WebSocket client API usually performs the handshake then returns a wrapper
     65 around the network socket and the :class:`~client.ClientProtocol`.
     66 
     67 Server-side
     68 ...........
     69 
     70 If you're building a server, accept network connections from clients and
     71 perform a TLS handshake if desired.
     72 
     73 For each connection, initialize a :class:`~server.ServerProtocol`::
     74 
     75    from websockets.server import ServerProtocol
     76 
     77    protocol = ServerProtocol()
     78 
     79 Once you receive enough data, as explained in `Receive data`_ below, the first
     80 event returned by :meth:`~protocol.Protocol.events_received` is the WebSocket
     81 handshake request.
     82 
     83 Create a WebSocket handshake response
     84 with :meth:`~server.ServerProtocol.accept` and send it
     85 with :meth:`~server.ServerProtocol.send_response`::
     86 
     87    response = protocol.accept(request)
     88    protocol.send_response(response)
     89 
     90 Alternatively, you may reject the WebSocket handshake and return an HTTP
     91 response with :meth:`~server.ServerProtocol.reject`::
     92 
     93    response = protocol.reject(status, explanation)
     94    protocol.send_response(response)
     95 
     96 Then, call :meth:`~protocol.Protocol.data_to_send` and send its output to
     97 the network, as described in `Send data`_ below.
     98 
     99 Even when you call :meth:`~server.ServerProtocol.accept`, the WebSocket
    100 handshake may fail if the request is incorrect or unsupported.
    101 
    102 When the handshake fails, the reason is available in
    103 :attr:`~server.ServerProtocol.handshake_exc`::
    104 
    105    if protocol.handshake_exc is not None:
    106        raise protocol.handshake_exc
    107 
    108 Else, the WebSocket connection is open.
    109 
    110 A WebSocket server API usually builds a wrapper around the network socket and
    111 the :class:`~server.ServerProtocol`. Then it invokes a connection handler that
    112 accepts the wrapper in argument.
    113 
    114 It may also provide a way to close all connections and to shut down the server
    115 gracefully.
    116 
    117 Going forwards, this guide focuses on handling an individual connection.
    118 
    119 From the network to the application
    120 -----------------------------------
    121 
    122 Go through the five steps below until you reach the end of the data stream.
    123 
    124 Receive data
    125 ............
    126 
    127 When receiving data from the network, feed it to the protocol's
    128 :meth:`~protocol.Protocol.receive_data` method.
    129 
    130 When reaching the end of the data stream, call the protocol's
    131 :meth:`~protocol.Protocol.receive_eof` method.
    132 
    133 For example, if ``sock`` is a :obj:`~socket.socket`::
    134 
    135    try:
    136        data = sock.recv(65536)
    137    except OSError:  # socket closed
    138        data = b""
    139    if data:
    140        protocol.receive_data(data)
    141    else:
    142        protocol.receive_eof()
    143 
    144 These methods aren't expected to raise exceptions — unless you call them again
    145 after calling :meth:`~protocol.Protocol.receive_eof`, which is an error.
    146 (If you get an exception, please file a bug!)
    147 
    148 Send data
    149 .........
    150 
    151 Then, call :meth:`~protocol.Protocol.data_to_send` and send its output to
    152 the network::
    153 
    154    for data in protocol.data_to_send():
    155        if data:
    156            sock.sendall(data)
    157        else:
    158            sock.shutdown(socket.SHUT_WR)
    159 
    160 The empty bytestring signals the end of the data stream. When you see it, you
    161 must half-close the TCP connection.
    162 
    163 Sending data right after receiving data is necessary because websockets
    164 responds to ping frames, close frames, and incorrect inputs automatically.
    165 
    166 Expect TCP connection to close
    167 ..............................
    168 
    169 Closing a WebSocket connection normally involves a two-way WebSocket closing
    170 handshake. Then, regardless of whether the closure is normal or abnormal, the
    171 server starts the four-way TCP closing handshake. If the network fails at the
    172 wrong point, you can end up waiting until the TCP timeout, which is very long.
    173 
    174 To prevent dangling TCP connections when you expect the end of the data stream
    175 but you never reach it, call :meth:`~protocol.Protocol.close_expected`
    176 and, if it returns :obj:`True`, schedule closing the TCP connection after a
    177 short timeout::
    178 
    179    # start a new execution thread to run this code
    180    sleep(10)
    181    sock.close()  # does nothing if the socket is already closed
    182 
    183 If the connection is still open when the timeout elapses, closing the socket
    184 makes the execution thread that reads from the socket reach the end of the
    185 data stream, possibly with an exception.
    186 
    187 Close TCP connection
    188 ....................
    189 
    190 If you called :meth:`~protocol.Protocol.receive_eof`, close the TCP
    191 connection now. This is a clean closure because the receive buffer is empty.
    192 
    193 After :meth:`~protocol.Protocol.receive_eof` signals the end of the read
    194 stream, :meth:`~protocol.Protocol.data_to_send` always signals the end of
    195 the write stream, unless it already ended. So, at this point, the TCP
    196 connection is already half-closed. The only reason for closing it now is to
    197 release resources related to the socket.
    198 
    199 Now you can exit the loop relaying data from the network to the application.
    200 
    201 Receive events
    202 ..............
    203 
    204 Finally, call :meth:`~protocol.Protocol.events_received` to obtain events
    205 parsed from the data provided to :meth:`~protocol.Protocol.receive_data`::
    206 
    207    events = connection.events_received()
    208 
    209 The first event will be the WebSocket opening handshake request or response.
    210 See `Opening a connection`_ above for details.
    211 
    212 All later events are WebSocket frames. There are two types of frames:
    213 
    214 * Data frames contain messages transferred over the WebSocket connections. You
    215  should provide them to the application. See `Fragmentation`_ below for
    216  how to reassemble messages from frames.
    217 * Control frames provide information about the connection's state. The main
    218  use case is to expose an abstraction over ping and pong to the application.
    219  Keep in mind that websockets responds to ping frames and close frames
    220  automatically. Don't duplicate this functionality!
    221 
    222 From the application to the network
    223 -----------------------------------
    224 
    225 The connection object provides one method for each type of WebSocket frame.
    226 
    227 For sending a data frame:
    228 
    229 * :meth:`~protocol.Protocol.send_continuation`
    230 * :meth:`~protocol.Protocol.send_text`
    231 * :meth:`~protocol.Protocol.send_binary`
    232 
    233 These methods raise :exc:`~exceptions.ProtocolError` if you don't set
    234 the :attr:`FIN <websockets.frames.Frame.fin>` bit correctly in fragmented
    235 messages.
    236 
    237 For sending a control frame:
    238 
    239 * :meth:`~protocol.Protocol.send_close`
    240 * :meth:`~protocol.Protocol.send_ping`
    241 * :meth:`~protocol.Protocol.send_pong`
    242 
    243 :meth:`~protocol.Protocol.send_close` initiates the closing handshake.
    244 See `Closing a connection`_ below for details.
    245 
    246 If you encounter an unrecoverable error and you must fail the WebSocket
    247 connection, call :meth:`~protocol.Protocol.fail`.
    248 
    249 After any of the above, call :meth:`~protocol.Protocol.data_to_send` and
    250 send its output to the network, as shown in `Send data`_ above.
    251 
    252 If you called :meth:`~protocol.Protocol.send_close`
    253 or :meth:`~protocol.Protocol.fail`, you expect the end of the data
    254 stream. You should follow the process described in `Close TCP connection`_
    255 above in order to prevent dangling TCP connections.
    256 
    257 Closing a connection
    258 --------------------
    259 
    260 Under normal circumstances, when a server wants to close the TCP connection:
    261 
    262 * it closes the write side;
    263 * it reads until the end of the stream, because it expects the client to close
    264  the read side;
    265 * it closes the socket.
    266 
    267 When a client wants to close the TCP connection:
    268 
    269 * it reads until the end of the stream, because it expects the server to close
    270  the read side;
    271 * it closes the write side;
    272 * it closes the socket.
    273 
    274 Applying the rules described earlier in this document gives the intended
    275 result. As a reminder, the rules are:
    276 
    277 * When :meth:`~protocol.Protocol.data_to_send` returns the empty
    278  bytestring, close the write side of the TCP connection.
    279 * When you reach the end of the read stream, close the TCP connection.
    280 * When :meth:`~protocol.Protocol.close_expected` returns :obj:`True`, if
    281  you don't reach the end of the read stream quickly, close the TCP connection.
    282 
    283 Fragmentation
    284 -------------
    285 
    286 WebSocket messages may be fragmented. Since this is a protocol-level concern,
    287 you may choose to reassemble fragmented messages before handing them over to
    288 the application.
    289 
    290 To reassemble a message, read data frames until you get a frame where
    291 the :attr:`FIN <websockets.frames.Frame.fin>` bit is set, then concatenate
    292 the payloads of all frames.
    293 
    294 You will never receive an inconsistent sequence of frames because websockets
    295 raises a :exc:`~exceptions.ProtocolError` and fails the connection when this
    296 happens. However, you may receive an incomplete sequence if the connection
    297 drops in the middle of a fragmented message.
    298 
    299 Tips
    300 ----
    301 
    302 Serialize operations
    303 ....................
    304 
    305 The Sans-I/O layer expects to run sequentially. If your interact with it from
    306 multiple threads or coroutines, you must ensure correct serialization. This
    307 should happen automatically in a cooperative multitasking environment.
    308 
    309 However, you still have to make sure you don't break this property by
    310 accident. For example, serialize writes to the network
    311 when :meth:`~protocol.Protocol.data_to_send` returns multiple values to
    312 prevent concurrent writes from interleaving incorrectly.
    313 
    314 Avoid buffers
    315 .............
    316 
    317 The Sans-I/O layer doesn't do any buffering. It makes events available in
    318 :meth:`~protocol.Protocol.events_received` as soon as they're received.
    319 
    320 You should make incoming messages available to the application immediately and
    321 stop further processing until the application fetches them. This will usually
    322 result in the best performance.