Set up a simple HTTPS server with asyncio

Overview

I've set up a simple HTTPS server to practice the asyncio module for event loops and the uvloop. uvloop is a module based on asyncio and libuv. Since 2016, new micro-frameworks such as Sanic and japronto that have adopted uvloop have emerged.

Premise

It assumes Python 3.6. In Python 3.6, the SSLContext default values for the ssl module have been changed and constants have been consolidated.

About uvloop

uvloop implements ʻasyncio.AbstractEventLoop` and provides an API compatible with uvloop. Due to libuv constraints, uvloop does not support Windows, so asyncio is responsible for the uvloop fallback.

Create a self-signed certificate

You can create a self-signed certificate with the following one-liner.

# https://stackoverflow.com/a/41366949/531320
openssl req -x509 -newkey rsa:4096 -sha256 \
-nodes -keyout server.key -out server.crt \
-subj "/CN=example.com" -days 3650

Set up an HTTPS server

Let's set up an echo server that returns a string regardless of the HTTP method.

server.py


import asyncio
import ssl

async def request_handler(reader, writer):
    msg = (
      'HTTP/1.1 200 OK\r\n'
      'Content-Type: text/plain; charset=utf-8\r\n'
      '\r\n'
      'hello\r\n'
    )
    writer.write(msg.encode())
    await writer.drain()
    writer.close()

host = '127.0.0.1'
port = 8000

ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ctx.load_cert_chain('server.crt', keyfile='server.key')
ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1

loop = asyncio.get_event_loop()
coro = asyncio.start_server(
  request_handler, 
  host, port, ssl=ctx, loop=loop
)
server = loop.run_until_complete(coro)

print('Serving on {}'.format(server.sockets[0].getsockname()))

try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

Create an HTTPS client

Now let's create an HTTPS client.

client.py


import asyncio
import ssl

async def http_client(host, port, msg, ctx, loop):
    reader, writer = await asyncio.open_connection(
        host, port, ssl=ctx, loop=loop
    )

    writer.write(msg.encode())
    data = await reader.read()
    print("Received: %r" % data.decode())
    writer.close()

host = '127.0.0.1'
port = 8000
msg = (
  'GET / HTTP/1.1\r\n'
  'Host: localhost:8000\r\n'
  '\r\n'
  '\r\n'
)

ctx = ssl.create_default_context()
ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

loop = asyncio.get_event_loop()
loop.run_until_complete(http_client(host, port, msg, ctx, loop))
loop.close()

aiohttp

aiohttp is an HTTP module developed based on asyncio, and also comes with application development functions. The installation is as follows:

pip3 install aiohttp

Let's set up a server that displays HTML files.

server.py


from aiohttp import web
from pathlib import Path
import ssl

host='localhost'
port=8000
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ctx.load_cert_chain('server.crt', keyfile='server.key')
ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1

app = web.Application()
app.router.add_static('/static', path=str(Path.cwd().joinpath('static')), show_index=True)
web.run_app(app, host=host, port=port, ssl_context=ctx)

Recommended Posts

Set up a simple HTTPS server with asyncio
Set up a simple HTTPS server in Python 3
[Vagrant] Set up a simple API server with python
Set up a Samba server with Docker
Set up a local server with Go-File upload-
Set up a local server with Go-File download-
Set up a simple SMTP server in Python
Set up a simple local server on your Mac
Set up a web server with CentOS7 + Anaconda + Django + Apache
Set up a mail server using Twisted
Set up Ubuntu as a Linux cheat sheet and https server
Send mail with mailx to a dummy SMTP server set up with python.
Start a simple Python web server with Docker
Set up a test SMTP server in Python.
Set up a UDP server in C language
Set up reverse proxy to https server with CentOS Linux 8 + Apache mod_ssl
How to set up a local development server
Introduction and usage of Python bottle ・ Try to set up a simple web server with login function
Set up a Minecraft resource (Spigot) server via docker (2)
Set up a file server on Ubuntu 20.04 using Samba
Set up a free server on AWS in 30 minutes
[Part 1] Let's set up a Minecraft server on Linux
Set up a Minecraft resource (Spigot) server via docker
Set up a Python development environment with Sublime Text 2
Create a (simple) REST server
Create a simple textlint server
Set up a Python development environment with Visual Studio Code
Reload the server set up with gunicorn when changing the code
How to set up a simple SMTP server that can be tested locally in Python
Set up social login with Django
Set up pygit2 with static link
Creating a Flask server with Docker
Creating a simple app with flask
Write a super simple TCP server
Creating a simple PowerPoint file with Python
A simple RSS reader made with Django
Build a simple WebDAV server on Linux
Set up a Lambda function and let it work with S3 events!
Draw a Mandelbrot set with Brainf * ck
Let's make a simple language with PLY 1
Create a simple web app with flask
Set up a local web server in 30 seconds using python 3's http.server
Set up a server that processes multiple connections at the same time
I made a simple blackjack with Python
Put Docker in Windows Home and run a simple web server with Python
Start a temporary http server locally with Pytest
Build a local server with a single command [Mac]
Install Windows 10 from a Linux server with PXE
Set up golang with goenv on GNU / Linux
Make a simple pixel art generator with Flask
Pretend to be a server with two PCs
[Python] Make a simple maze game with Pyxel
I made a simple Bitcoin wallet with pycoin
Launch a web server with Python and Flask
Set up a Python development environment on Marvericks
A simple to-do list created with Python + Django
Mount a directory on another server with sshfs
Create a "Hello World" (HTTP) server with Tornado
How to set up a Google Colab environment with Coursera's advanced machine learning courses
Set up a file server using samba on ZeroPi of Friendly Arm [OS installation]
[Mac] I want to make a simple HTTP server that runs CGI with Python