Name Description Size
asyncio-server.py asyncio-server.py ~~~~~~~~~~~~~~~~~ A fully-functional HTTP/2 server using asyncio. Requires Python 3.5+. This example demonstrates handling requests with bodies, as well as handling those without. In particular, it demonstrates the fact that DataReceived may be called multiple times, and that applications must handle that possibility. 7261
cert.crt 1281
cert.key 1679
wsgi-server.py asyncio-server.py ~~~~~~~~~~~~~~~~~ A fully-functional WSGI server, written using h2. Requires asyncio. To test it, try installing httpbin from pip (``pip install httpbin``) and then running the server (``python asyncio-server.py httpbin:app``). This server does not support HTTP/1.1: it is a HTTP/2-only WSGI server. The purpose of this code is to demonstrate how to integrate h2 into a more complex application, and to demonstrate several principles of concurrent programming. The architecture looks like this: +---------------------------------+ | 1x HTTP/2 Server Thread | | (running asyncio) | +---------------------------------+ +---------------------------------+ | N WSGI Application Threads | | (no asyncio) | +---------------------------------+ Essentially, we spin up an asyncio-based event loop in the main thread. This launches one HTTP/2 Protocol instance for each inbound connection, all of which will read and write data from within the main thread in an asynchronous manner. When each HTTP request comes in, the server will build the WSGI environment dictionary and create a ``Stream`` object. This object will hold the relevant state for the request/response pair and will act as the WSGI side of the logic. That object will then be passed to a background thread pool, and when a worker is available the WSGI logic will begin to be executed. This model ensures that the asyncio web server itself is never blocked by the WSGI application. The WSGI application and the HTTP/2 server communicate via an asyncio queue, together with locks and threading events. The locks themselves are implicit in asyncio's "call_soon_threadsafe", which allows for a background thread to register an action with the main asyncio thread. When the asyncio thread eventually takes the action in question it sets as threading event, signaling to the background thread that it is free to continue its work. To make the WSGI application work with flow control, there is a very important invariant that must be observed. Any WSGI action that would cause data to be emitted to the network MUST be accompanied by a threading Event that is not set until that data has been written to the transport. This ensures that the WSGI application *blocks* until the data is actually sent. The reason we require this invariant is that the HTTP/2 server may choose to re-order some data chunks for flow control reasons: that is, the application for stream X may have actually written its data first, but the server may elect to send the data for stream Y first. This means that it's vital that there not be *two* writes for stream X active at any one point or they may get reordered, which would be particularly terrible. Thus, the server must cooperate to ensure that each threading event only fires when the *complete* data for that event has been written to the asyncio transport. Any earlier will cause untold craziness. 31177