Skip to content

romanvm/WsgiBoostServer

Repository files navigation

WsgiBoostServer

image

image

The project is closed!

Unfortunately, I found out that using WsgiBoostServer with various Python packages that include compiled binary modules often leads to Python interpreter crashes because of interpreter memory corruption. This happens both on Windows and Linux. Since WsgiBoostServer follows (more or less) modern C++ best practices and does not use things like raw pointers and C-style arrays, this probably happens because some libraries (Boost.Asio?) do not work well inside a Python interpreter.

Since my C++ skills are limited, finding the root cause is beyond my abilities. Feel free to inspect the code (maybe I've missed something) or use it as a starting point for your own projects. WsgiBoostServer does work well with pure-Python WSGI applications and static files, after all.

In the future I may return to the project if by some happy chance I find out what is wrong with it. But for now I put it on hold. It was fun to code WsgiBoostServer and I learned a lot about C++ and Python in the process.

Information

WsgiBoostServer is an asynchronous multi-threaded WSGI and HTTP server written as a Python extension module in C++ using Boost.Asio and Pybind11 libraries. It can serve both Python WSGI applications and static files. Because it is written in C++, WsgiBoostServer is faster than pure Python solutions, like Waitress. It can be used for hosting Python micro-services and/or static files. WsgiBoostServer also supports HTTPS protocol.

In Releases section of this repository you can find compiled wheels with HTTPS support (statically linked against Boost libraries) for Python 3.6 on Windows (32 and 64 bit), for various Python 3 versions on Linux x64, and for Python 3.4 on Raspberry Pi 2 (if I'm not too lazy to compile this).

You can install those binary wheels into your Python environment with pip:

$pip install <link to a .whl file>

Main Features

WSGI Server:

  • Compliant with PEP-3333.
  • Releases GIL for pure C++ operations, allowing more effective multi-threading.
  • Uses Transfer-Encoding: chunked if a WSGI application does not provide Content-Length header (like Django by default).
  • Can be used as a regular module in any Python application.

HTTP Server:

  • Works on pure C++ level, effectively bypassing GIL.
  • Determines MIME for most file types.
  • Uses gzip compression for common textual formats: txt/html/xml/css/js/json.
  • Supports If-Modified-Since and If-None-Match headers.
  • Supports Range header.
  • Checks if requested files are really located within specified content folders to forbid requesting files by arbitrary paths (for security reasons).

Benchmarks

Performance benchmarks of WsgiBoostServer compared to pure-Python Waitress WSGI server and Node.js can be found here. According to those benchmarks WsgiBoostServer is about 2 times faster than Waitress and about 20% faster (with multiple threads) than Node.js.

Compatibility

  • OS: Windows, Linux. In theory, WsgiBoostServer can be built and used on any OS that has a C++ 11/14-compatible compiler and supports Python setuptools.
  • Python 3 (tested with 3.4, 3.5 and 3.6). Python 2 is no longer supported!
  • Boost: tested with 1.55 and above.
  • Compilers: GCC 4.9+, MS Visual Studio 2015 Update 3 and above.

Usage

Simple example with Flask micro-framework:

#!/usr/bin/env python

from flask import Flask
from wsgi_boost import WsgiBoostHttp

app = Flask(__name__)


# Simple Flask application
@app.route('/')
def hello_world():
    return 'Hello World!'


# Create a server on the port 8080 with 4 threads
httpd = WsgiBoostHttp(port=8080, threads=4)
# Set the WSGI app to serve
httpd.set_app(app)
# Serve static files from a directory
httpd.add_static_route(r'^/files', '/var/www/files')
httpd.start()

More advanced examples with Flask and Django frameworks can be found examples folder. Also see docstrings in wsgi_boost/wsgi_boost.cpp file for detailed information on WsgiBoostServer API.

HTTPS Support

WsgiBoostServer provides WsgiBoostHttps class that allows to serve your WSGI application and static files via a secure connection. To use HTTPS, in the preceding example you need to replace WsgiBoostHttp class with WsgiBoostHttps like this:

httpd = WsgiBoostHttps('fullchain.pem', 'privkey.pem', port=443, threads=4)
# Redirect all non-secure HTTP requests from port 80 (default) to HTTPS port
httpd.redirect_http = True

Here 'fullchain.pem' and 'privkey.pem' are paths to full HTTPS certificate chain and private key files respectively. If your private key is password-protected you can provide a password via HTTPS_KEY_PASS environment variable.

It is recommended to obtain a HTTPS certificate from a trusted Certificate Authority but for testing purposes you can create a self-signed certificate. Note that most programs won't accept such certificate with default security settings. For example, in browsers you need to add your site to browser's security exceptions. With curl you need to use -k option, and with Python requests library you need to provide verify=False argument to request functions.

Optionally, you can generate parameters for Diffie-Hellman key exchange:

$openssl dhparam -out dh.pem 2048

It is strongly recommended to use at least 2048 bit prime number length. A path to the generated file can be passed as the third positional parameter to WsgiBoostHttps constructor.

If you you want to get a free trusted certificate from Let's Enccrypt for a site hosted on WsgiBoostServer, you can use their certbot utility with --webroot option. In this case before obtaining a certificate you need to add a static route to --webroot-path folder:

httpd.add_static_route(r'^/\.well-known', '/path/to/webroot-dir')

Compilation

See compilation instructions.