A Simple Python HTTP Server
Although, we aren’t gonna need it in this article but it’s always good to setup a virtual environment when working with Python. Check out my article on how to create a virtual environment for Python: /blog/python/how-to-create-a-python-virtual-environment/.
To create a simple Python HTTP Server, we are going to use two modules called http.server and socketserver. They both are part of Python’s Standard Library, we don’t need to install them.
Important! This material is made for learning purposes. DO NOT use it in production. http.server is not recommended for production. It only implements basic security checks.
Let’s create a file called server.py and define our Server class there.
|
|
The preceding code-block will create a running server, listening, by default, on a port chosen by your OS and serving the current working directory.
How it works
On lines 8,9 the Server class initiates with two arguments - server_address and handler.
|
|
The server_address is a tuple taking two values. The first value is the host, which is 127.0.0.1 for localhost. The second value is the port number, which by default is 0, this allows the operating system to choose itself on which port to serve. The handler, by default, accepts SimpleHTTPRequestHandler class. SimpleHTTPRequestHandler is part of the http.server module and is responsible for handling the client requests.
You can see how the handler is used by a TCPServer instance on line 14. TCPServer itself is part of the socketserver module and instantiates with 3 arguments: server_address, RequestHandlerClass, and bind_and_activate. We’ll skip the bind_and_activate argument in this article. For the other two, you already understand what they do.
|
|
On line 15, we call server_address from the newly created TCPServer instance to print the server information on line 17. Here, the port number is set by the OS, already. We set serving_at as the variable name here to escape confusion with the variable on line 10.
|
|
On line 18, we call the serve_forever() method. It runs the server in a loop and never exits unless the program gets terminated.
|
|
Finally, on lines 21, 22 we instantiate the Server class and call its serve method.
|
|
Creating a custom handler
You can create a custom handler to be used by the TCPServer instead of SimpleHTTPRequestHandler. For simplicity, let’s define our handler in the same server.py file.
|
|
The Handler class inherits from SimpleHTTPRequestHandler. We keep it empty for now. You’ll see soon how we can customize it. Since we’ve defined a custom handler, the Server class instantiates with the handler attribute equal to our custom Handler class on line 25.
|
|
Serving a custom directory
Now, what if we want to serve on a different directory. Let’s say we have a directory called public containing a few HTML files and images. To serve that directory we must modify the Handler class defined in the previous passage.
|
|
Here, we initiate our Handler class by calling the __init__ of the parent class and modifying the directory argument of it. All other non-keyword and keyword arguments remain the same with *args and **kwargs called. It worths mentioning that in Python3.9 the directory argument accepts a path-like object.
Basic routing
SimpleHTTPRequestHandler class allows us to manage the requests coming from a client via do_GET(), do_POST() and do_HEAD() methods. Since our Handler class inherits from SimpleHTTPRequestHandler, we can define custom routes by overriding these methods. In this article, we do so only to do_GET() method and define custom routes for GET requests.
|
|
On lines 11-15, we say that if the root path (/) is requested then the server should look for the index.html file. And if the requested path is /lyrics, then the server should look for the lyrics.html file.
Notice the return statement at the end:
|
|
Since we override the do_GET() method, we must call the default one from the parent class at the end so the handler knows how to process the GET requests.
We can do more with do_GET() and even create automatic routing to look for the corresponding HTML files for each path, etc. But that’s a topic for another article or for you to experiment and find it out yourself. 🙂
The code in this article is available in my repo here: github.com/oorkan/a-simple-python-http-server.
I hope you enjoyed it. Cheers! 🍻
References
The Python Standard Library (@3.9, lup: March 20, 2021)
socketserver — A framework for network servers (@3.9, lup: March 20, 2021)
http.server — HTTP servers (@3.9, lup: March 20, 2021)
Python *args and **kwargs by Programiz