Source code for hyper2web.server

"""
A fully-functional HTTP/2 server written for curio.

Requires Python 3.5+.
"""

import traceback

from curio import spawn

import h2.config
import h2.connection
import h2.events
from h2.exceptions import ProtocolError

# hyper2web imports
from . import sslsocket, abstract, http
create_listening_ssl_socket = sslsocket.create_listening_ssl_socket
HTTP = http.HTTP


# todo: move this to app.App
[docs]async def h2_server(address, certfile, keyfile, app: abstract.AbstractApp): """ Create an HTTP/2 server at the given address. """ sock = create_listening_ssl_socket(address, certfile, keyfile) print("Now listening on %s:%d" % address) async with sock: while True: client, _ = await sock.accept() server = H2Server(client, app) await spawn(server.run())
[docs]class H2Server: """ This class just connects to socket and that's about it. Most heavy lifting is done by http.HTTP """ def __init__(self, sock, app: abstract.AbstractApp): config = h2.config.H2Configuration(client_side=False, header_encoding='utf-8') self.sock = sock self.conn = h2.connection.H2Connection(config=config) # the Application that needs this server # this server runs this app self.http = HTTP(app=app, sock=self.sock, connection=self.conn)
[docs] async def run(self): """ Loop over the connection, managing it appropriately. """ self.conn.initiate_connection() await self.sock.sendall(self.conn.data_to_send()) while True: # 65535 is basically arbitrary here: this amounts to "give me # whatever data you have". data = await self.sock.recv(65535) if not data: break try: events = self.conn.receive_data(data) except ProtocolError as e: # todo: add this to logger traceback.print_exception(etype=e, value=e, tb=e.__traceback__) continue except Exception as e: traceback.print_exception(etype=e, value=e, tb=e.__traceback__) print("Does not expect other exceptions. Exit.") exit() for event in events: await self.http.handle_event(event) await self.sock.sendall(self.conn.data_to_send())