1Negotiating HTTP/2
2==================
3
4`RFC 7540`_ specifies three methods of negotiating HTTP/2 connections. This document outlines how to use Hyper-h2 with each one.
5
6.. _starting-alpn:
7
8HTTPS URLs (ALPN)
9-------------------------
10
11Starting HTTP/2 for HTTPS URLs is outlined in `RFC 7540 Section 3.3`_. In this case, the client and server use a TLS extension to negotiate HTTP/2: `ALPN`_. How to use ALPN is currently not covered in this document: please consult the documentation for either the :mod:`ssl module <python:ssl>` in the standard library, or the :mod:`PyOpenSSL <pyopenssl:OpenSSL.SSL>` third-party modules, for more on this topic.
12
13This method is the simplest to use once the TLS connection is established. To use it with Hyper-h2, after you've established the connection and confirmed that HTTP/2 has been negotiated with `ALPN`_, create a :class:`H2Connection <h2.connection.H2Connection>` object and call :meth:`H2Connection.initiate_connection <h2.connection.H2Connection.initiate_connection>`. This will ensure that the appropriate preamble data is placed in the data buffer. You should then immediately send the data returned by :meth:`H2Connection.data_to_send <h2.connection.H2Connection.data_to_send>` on your TLS connection.
14
15At this point, you're free to use all the HTTP/2 functionality provided by Hyper-h2.
16
17.. note::
18   Although Hyper-h2 is not concerned with negotiating protocol versions, it is important to note that support for `ALPN`_ is not available in the standard library of Python versions < 2.7.9.
19   As a consequence, clients may encounter various errors due to protocol versions mismatch.
20
21Server Setup Example
22~~~~~~~~~~~~~~~~~~~~
23
24This example uses the APIs as defined in Python 3.5. If you are using an older version of Python you may not have access to the APIs used here. As noted above, please consult the documentation for the :mod:`ssl module <python:ssl>` to confirm.
25
26.. literalinclude:: ../../examples/fragments/server_https_setup_fragment.py
27   :language: python
28   :linenos:
29   :encoding: utf-8
30
31
32Client Setup Example
33~~~~~~~~~~~~~~~~~~~~
34
35The client example is very similar to the server example above. The :class:`SSLContext <python:ssl.SSLContext>` object requires some minor changes, as does the :class:`H2Connection <h2.connection.H2Connection>`, but the bulk of the code is the same.
36
37.. literalinclude:: ../../examples/fragments/client_https_setup_fragment.py
38   :language: python
39   :linenos:
40   :encoding: utf-8
41
42
43.. _starting-upgrade:
44
45HTTP URLs (Upgrade)
46-------------------
47
48Starting HTTP/2 for HTTP URLs is outlined in `RFC 7540 Section 3.2`_. In this case, the client and server use the HTTP Upgrade mechanism originally described in `RFC 7230 Section 6.7`_. The client sends its initial HTTP/1.1 request with two extra headers. The first is ``Upgrade: h2c``, which requests upgrade to cleartext HTTP/2. The second is a ``HTTP2-Settings`` header, which contains a specially formatted string that encodes a HTTP/2 Settings frame.
49
50To do this with Hyper-h2 you have two slightly different flows: one for clients, one for servers.
51
52Clients
53~~~~~~~
54
55For a client, when sending the first request you should manually add your ``Upgrade`` header. You should then create a :class:`H2Connection <h2.connection.H2Connection>` object and call :meth:`H2Connection.initiate_upgrade_connection <h2.connection.H2Connection.initiate_upgrade_connection>` with no arguments. This method will return a bytestring to use as the value of your ``HTTP2-Settings`` header.
56
57If the server returns a ``101`` status code, it has accepted the upgrade, and you should immediately send the data returned by :meth:`H2Connection.data_to_send <h2.connection.H2Connection.data_to_send>`. Now you should consume the entire ``101`` header block. All data after the ``101`` header block is HTTP/2 data that should be fed directly to :meth:`H2Connection.receive_data <h2.connection.H2Connection.receive_data>` and handled as normal with Hyper-h2.
58
59If the server does not return a ``101`` status code then it is not upgrading. Continue with HTTP/1.1 as normal: you may throw away your :class:`H2Connection <h2.connection.H2Connection>` object, as it is of no further use.
60
61The server will respond to your original request in HTTP/2. Please pay attention to the events received from Hyper-h2, as they will define the server's response.
62
63Client Example
64^^^^^^^^^^^^^^
65
66The code below demonstrates how to handle a plaintext upgrade from the perspective of the client. For the purposes of keeping the example code as simple and generic as possible it uses the synchronous socket API that comes with the Python standard library: if you want to use asynchronous I/O, you will need to translate this code to the appropriate idiom.
67
68.. literalinclude:: ../../examples/fragments/client_upgrade_fragment.py
69   :language: python
70   :linenos:
71   :encoding: utf-8
72
73
74Servers
75~~~~~~~
76
77If the first request you receive on a connection from the client contains an ``Upgrade`` header with the ``h2c`` token in it, and you're willing to upgrade, you should create a :class:`H2Connection <h2.connection.H2Connection>` object and call :meth:`H2Connection.initiate_upgrade_connection <h2.connection.H2Connection.initiate_upgrade_connection>` with the value of the ``HTTP2-Settings`` header (as a bytestring) as the only argument.
78
79Then, you should send back a ``101`` response that contains ``h2c`` in the ``Upgrade`` header. That response will inform the client that you're switching to HTTP/2. Then, you should immediately send the data that is returned to you by :meth:`H2Connection.data_to_send <h2.connection.H2Connection.data_to_send>` on the connection: this is a necessary part of the HTTP/2 upgrade process.
80
81At this point, you may now respond to the original HTTP/1.1 request in HTTP/2 by calling the appropriate methods on the :class:`H2Connection <h2.connection.H2Connection>` object. No further HTTP/1.1 may be sent on this connection: from this point onward, all data sent by you and the client will be HTTP/2 data.
82
83Server Example
84^^^^^^^^^^^^^^
85
86The code below demonstrates how to handle a plaintext upgrade from the perspective of the server. For the purposes of keeping the example code as simple and generic as possible it uses the synchronous socket API that comes with the Python standard library: if you want to use asynchronous I/O, you will need to translate this code to the appropriate idiom.
87
88.. literalinclude:: ../../examples/fragments/server_upgrade_fragment.py
89   :language: python
90   :linenos:
91   :encoding: utf-8
92
93
94Prior Knowledge
95---------------
96
97It's possible that you as a client know that a particular server supports HTTP/2, and that you do not need to perform any of the negotiations described above. In that case, you may follow the steps in :ref:`starting-alpn`, ignoring all references to ALPN: there's no need to perform the upgrade dance described in :ref:`starting-upgrade`.
98
99.. _RFC 7540: https://tools.ietf.org/html/rfc7540
100.. _RFC 7540 Section 3.2: https://tools.ietf.org/html/rfc7540#section-3.2
101.. _RFC 7540 Section 3.3: https://tools.ietf.org/html/rfc7540#section-3.3
102.. _ALPN: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
103.. _RFC 7230 Section 6.7: https://tools.ietf.org/html/rfc7230#section-6.7
104