1 27
import trio
2 27
import ssl
3

4 27
from ._highlevel_open_tcp_stream import DEFAULT_DELAY
5

6

7
# It might have been nice to take a ssl_protocols= argument here to set up
8
# NPN/ALPN, but to do this we have to mutate the context object, which is OK
9
# if it's one we created, but not OK if it's one that was passed in... and
10
# the one major protocol using NPN/ALPN is HTTP/2, which mandates that you use
11
# a specially configured SSLContext anyway! I also thought maybe we could copy
12
# the given SSLContext and then mutate the copy, but it's no good as SSLContext
13
# objects can't be copied: https://bugs.python.org/issue33023.
14
# So... let's punt on that for now. Hopefully we'll be getting a new Python
15
# TLS API soon and can revisit this then.
16 27
async def open_ssl_over_tcp_stream(
17
    host,
18
    port,
19
    *,
20
    https_compatible=False,
21
    ssl_context=None,
22
    # No trailing comma b/c bpo-9232 (fixed in py36)
23
    happy_eyeballs_delay=DEFAULT_DELAY,
24
):
25
    """Make a TLS-encrypted Connection to the given host and port over TCP.
26

27
    This is a convenience wrapper that calls :func:`open_tcp_stream` and
28
    wraps the result in an :class:`~trio.SSLStream`.
29

30
    This function does not perform the TLS handshake; you can do it
31
    manually by calling :meth:`~trio.SSLStream.do_handshake`, or else
32
    it will be performed automatically the first time you send or receive
33
    data.
34

35
    Args:
36
      host (bytes or str): The host to connect to. We require the server
37
          to have a TLS certificate valid for this hostname.
38
      port (int): The port to connect to.
39
      https_compatible (bool): Set this to True if you're connecting to a web
40
          server. See :class:`~trio.SSLStream` for details. Default:
41
          False.
42
      ssl_context (:class:`~ssl.SSLContext` or None): The SSL context to
43
          use. If None (the default), :func:`ssl.create_default_context`
44
          will be called to create a context.
45
      happy_eyeballs_delay (float): See :func:`open_tcp_stream`.
46

47
    Returns:
48
      trio.SSLStream: the encrypted connection to the server.
49

50
    """
51 27
    tcp_stream = await trio.open_tcp_stream(
52
        host, port, happy_eyeballs_delay=happy_eyeballs_delay
53
    )
54 27
    if ssl_context is None:
55 27
        ssl_context = ssl.create_default_context()
56 27
    return trio.SSLStream(
57
        tcp_stream, ssl_context, server_hostname=host, https_compatible=https_compatible
58
    )
59

60

61 27
async def open_ssl_over_tcp_listeners(
62
    port, ssl_context, *, host=None, https_compatible=False, backlog=None
63
):
64
    """Start listening for SSL/TLS-encrypted TCP connections to the given port.
65

66
    Args:
67
      port (int): The port to listen on. See :func:`open_tcp_listeners`.
68
      ssl_context (~ssl.SSLContext): The SSL context to use for all incoming
69
          connections.
70
      host (str, bytes, or None): The address to bind to; use ``None`` to bind
71
          to the wildcard address. See :func:`open_tcp_listeners`.
72
      https_compatible (bool): See :class:`~trio.SSLStream` for details.
73
      backlog (int or None): See :func:`open_tcp_listeners` for details.
74

75
    """
76 27
    tcp_listeners = await trio.open_tcp_listeners(port, host=host, backlog=backlog)
77 27
    ssl_listeners = [
78
        trio.SSLListener(tcp_listener, ssl_context, https_compatible=https_compatible)
79
        for tcp_listener in tcp_listeners
80
    ]
81 27
    return ssl_listeners
82

83

84 27
async def serve_ssl_over_tcp(
85
    handler,
86
    port,
87
    ssl_context,
88
    *,
89
    host=None,
90
    https_compatible=False,
91
    backlog=None,
92
    handler_nursery=None,
93
    task_status=trio.TASK_STATUS_IGNORED,
94
):
95
    """Listen for incoming TCP connections, and for each one start a task
96
    running ``handler(stream)``.
97

98
    This is a thin convenience wrapper around
99
    :func:`open_ssl_over_tcp_listeners` and :func:`serve_listeners` – see them
100
    for full details.
101

102
    .. warning::
103

104
       If ``handler`` raises an exception, then this function doesn't do
105
       anything special to catch it – so by default the exception will
106
       propagate out and crash your server. If you don't want this, then catch
107
       exceptions inside your ``handler``, or use a ``handler_nursery`` object
108
       that responds to exceptions in some other way.
109

110
    When used with ``nursery.start`` you get back the newly opened listeners.
111
    See the documentation for :func:`serve_tcp` for an example where this is
112
    useful.
113

114
    Args:
115
      handler: The handler to start for each incoming connection. Passed to
116
          :func:`serve_listeners`.
117

118
      port (int): The port to listen on. Use 0 to let the kernel pick
119
          an open port. Ultimately passed to :func:`open_tcp_listeners`.
120

121
      ssl_context (~ssl.SSLContext): The SSL context to use for all incoming
122
          connections. Passed to :func:`open_ssl_over_tcp_listeners`.
123

124
      host (str, bytes, or None): The address to bind to; use ``None`` to bind
125
          to the wildcard address. Ultimately passed to
126
          :func:`open_tcp_listeners`.
127

128
      https_compatible (bool): Set this to True if you want to use
129
          "HTTPS-style" TLS. See :class:`~trio.SSLStream` for details.
130

131
      backlog (int or None): See :class:`~trio.SSLStream` for details.
132

133
      handler_nursery: The nursery to start handlers in, or None to use an
134
          internal nursery. Passed to :func:`serve_listeners`.
135

136
      task_status: This function can be used with ``nursery.start``.
137

138
    Returns:
139
      This function only returns when cancelled.
140

141
    """
142 27
    listeners = await trio.open_ssl_over_tcp_listeners(
143
        port,
144
        ssl_context,
145
        host=host,
146
        https_compatible=https_compatible,
147
        backlog=backlog,
148
    )
149 27
    await trio.serve_listeners(
150
        handler, listeners, handler_nursery=handler_nursery, task_status=task_status
151
    )

Read our documentation on viewing source code .

Loading