Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Truly non-blocking HTTPS Server in Python

Tags:

python

http

ssl

I'm trying to build a truly non-blocking HTTPS server in Python. The following minimal code works just fine if everyone is playing nice:

import BaseHTTPServer
import SimpleHTTPServer
import SocketServer
import ssl 

class ThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
    pass

httpd = ThreadedHTTPServer(('localhost', 4443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile="localhost.key", certfile="localhost.pem", server_side=True)
httpd.serve_forever()

However, the problem is that this server blocks at least during the TLS handshake.

Test with:

$ nc localhost 4443  # leave this open

And then (in another terminal):

$ wget --no-check-certificate https://localhost:4443/
--2014-10-23 16:55:54--  https://localhost:4443/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:4443... connected.

The wget process blocks, indicating that something is blocked in the server. Once I close the nc process, wget continues. This is obviously not practical at all.

How do I get a truly non-blocking HTTPS server in Python, preferably without additional third-party software?

I should mention that the very same code works as expected without TLS (i.e., without the wrap_socket line).


Steffen Ullrich pointed out how to do it: pass do_handshake_on_connect=False to wrap_socket, then do the handshake yourself. In this case, subclass BaseHTTPServer.HTTPServer, override handle, and then do the handshake as shown in the Python docs (the socket is called self.request) followed by calling the super method.

like image 219
discardo Avatar asked Oct 23 '14 15:10

discardo


People also ask

Does Python have non-blocking IO?

These are pure-python functions which perform non-blocking I/O in python. nonblock_read provides the ability to read anything available on a buffer, like a file or a pipe or a socket, in a non-blocking fashion. Methods like readline will block until a newline is printed, etc.

How do I create a non-blocking socket in python?

In Python, you use socket. setblocking(False) to make it non-blocking.

What is non-blocking HTTP server?

A Non-Blocking server means that it is able to have multiple requests in progress at the same time by the same process or thread because it uses Non-Blocking I/O. In the Non-Blocking approach – one thread can handle multiple queries at a time.


1 Answers

You have to do a non-blocking SSL accept by calling ssl.wrap_socket with do_handshake_on_connect=False and later calling do_handshake yourself until it succeeds. See https://docs.python.org/3/library/ssl.html#notes-on-non-blocking-sockets.

You might also simply use Tornado which is a web server written in python and which also does fully non-blocking SSL handling. Even if you don't want to use it yourself you might have a look at the source code to see how this is done (search for do_handshake).

like image 86
Steffen Ullrich Avatar answered Oct 30 '22 09:10

Steffen Ullrich