Python’s http.server
module provides a straightforward way to create basic HTTP servers. This module is incredibly useful for development, testing, and simple file sharing. While not intended for production environments due to security limitations, it offers a quick and easy solution for local server needs. This article will explore the ins and outs of http.server
, covering its core classes, functionalities, and how to get a server running with just a few lines of Python code.
Understanding the http.server
Module
The http.server
module in Python is built upon the foundation of the socketserver
module, providing classes to implement HTTP servers. It’s designed to be simple and functional, offering essential features for handling HTTP requests. However, it’s crucial to understand its limitations, especially concerning security, before deploying it in any public-facing scenario.
Core Classes: HTTPServer
, ThreadingHTTPServer
, and BaseHTTPRequestHandler
At the heart of http.server
are several key classes that work together to create and manage HTTP servers.
-
HTTPServer(server_address, RequestHandlerClass)
: This is the foundational class for creating HTTP servers. It’s a subclass ofsocketserver.TCPServer
, responsible for listening on a specified socket for HTTP requests and dispatching these requests to a designated handler class. Theserver_address
is a tuple containing the host and port for the server to listen on. TheRequestHandlerClass
is a class that will handle each incoming request. A basic example of setting up and running anHTTPServer
is as follows:from http.server import HTTPServer, BaseHTTPRequestHandler def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler): server_address = ('', 8000) # '' means listen on all interfaces httpd = server_class(server_address, handler_class) httpd.serve_forever() if __name__ == '__main__': run()
This code snippet demonstrates the basic structure for initiating an HTTP server. It defines a
run
function that takes a server class and a handler class as arguments, sets up the server address, instantiates the server, and then starts the server to listen indefinitely for incoming requests usingserve_forever()
. -
ThreadingHTTPServer(server_address, RequestHandlerClass)
: This class extendsHTTPServer
by incorporating threading capabilities usingsocketserver.ThreadingMixIn
. This is particularly beneficial for handling multiple concurrent requests, which is common in web browsing scenarios where browsers might pre-open sockets.ThreadingHTTPServer
ensures that the server can handle these simultaneous connections without blocking, improving responsiveness. It’s used in the same way asHTTPServer
, simply substitutingHTTPServer
withThreadingHTTPServer
in your server initialization:from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler def run(server_class=ThreadingHTTPServer, handler_class=BaseHTTPRequestHandler): server_address = ('', 8000) httpd = server_class(server_address, handler_class) httpd.serve_forever() if __name__ == '__main__': run()
By using
ThreadingHTTPServer
, you enhance the server’s ability to manage multiple requests efficiently, making it more suitable for scenarios where concurrency is expected. -
BaseHTTPRequestHandler(request, client_address, server)
: This is the handler class that processes the actual HTTP requests. It’s an abstract class and doesn’t provide specific responses to HTTP requests on its own. Instead, it’s designed to be subclassed.BaseHTTPRequestHandler
parses incoming requests and then calls specific methods based on the request type, such asdo_GET()
for GET requests ordo_POST()
for POST requests. It provides several instance variables that are crucial for request handling:client_address
: A tuple containing the client’s IP address and port.server
: A reference to the server instance.close_connection
: A boolean indicating whether to close the connection after handling the current request.requestline
: The raw HTTP request line string.command
: The HTTP command (e.g., ‘GET’, ‘POST’).path
: The requested path from the URL.request_version
: The HTTP version from the request.headers
: An instance ofhttp.client.HTTPMessage
containing the request headers.rfile
: A buffered input stream for reading the request body.wfile
: A buffered output stream for writing the response.
To create a functional HTTP server, you need to subclass
BaseHTTPRequestHandler
and override methods likedo_GET()
anddo_POST()
to define how your server should respond to different types of HTTP requests.
Request Handlers: SimpleHTTPRequestHandler
and CGIHTTPRequestHandler
The http.server
module provides two concrete implementations of request handler classes that extend BaseHTTPRequestHandler
:
-
SimpleHTTPRequestHandler(request, client_address, server, directory=None)
: This handler is designed to serve files directly from a specified directory, or the current directory if none is provided. It maps the requested URL path to the local file system.SimpleHTTPRequestHandler
implementsdo_GET()
anddo_HEAD()
methods to serve files. When a request targets a directory, it looks forindex.html
orindex.htm
files to serve as the directory index. If no index file is found, it can generate a directory listing. This handler is extremely useful for quickly sharing files over HTTP, making it ideal for development and testing scenarios.To use
SimpleHTTPRequestHandler
, you would include it as the handler class when creating yourHTTPServer
orThreadingHTTPServer
:from http.server import HTTPServer, SimpleHTTPRequestHandler def run(server_class=HTTPServer, handler_class=SimpleHTTPRequestHandler): server_address = ('', 8000) httpd = server_class(server_address, handler_class) print(f"Serving at port {server_address[1]}") httpd.serve_forever() if __name__ == '__main__': run()
This setup will serve files from the directory where you run the script. You can navigate to
http://localhost:8000
in your browser to access these files.The
SimpleHTTPRequestHandler
also includes features like handlingIf-Modified-Since
headers to improve efficiency by avoiding resending files that haven’t been changed since the last request. It also correctly guesses MIME types based on file extensions using a built-inextensions_map
. -
CGIHTTPRequestHandler(request, client_address, server)
: This handler extendsSimpleHTTPRequestHandler
to also serve CGI (Common Gateway Interface) scripts. CGI allows the server to execute scripts in real-time and return the output as HTTP responses.CGIHTTPRequestHandler
is configured to run CGI scripts located in specific directories, by default/cgi-bin
and/htbin
. When a request targets a file within these directories, it’s treated as a CGI script and executed. The output from the script is then sent back to the client.CGIHTTPRequestHandler
supports bothdo_GET()
anddo_POST()
methods for CGI scripts. However, it’s important to note that CGI is an older technology and has significant performance and security implications compared to modern web frameworks.To enable CGI handling, you would use
CGIHTTPRequestHandler
as the handler class:from http.server import HTTPServer, CGIHTTPRequestHandler def run(server_class=HTTPServer, handler_class=CGIHTTPRequestHandler): server_address = ('', 8000) httpd = server_class(server_address, handler_class) print(f"Serving CGI scripts at port {server_address[1]}") httpd.serve_forever() if __name__ == '__main__': run()
To use CGI scripts, you’d need to place them in a directory named
cgi-bin
(orhtbin
) within your server’s root directory. These scripts must be executable and should output HTTP headers followed by the content.Important Deprecation Note: It’s critical to be aware that
CGIHTTPRequestHandler
is deprecated as of Python 3.13 and will be removed in Python 3.15. CGI is no longer considered a best practice for web development due to its inefficiencies and security concerns. Modern Python web frameworks offer much better alternatives for dynamic web content.
Creating Your First HTTP Server in Python
Let’s walk through creating a basic HTTP server using http.server
. We’ll start with the simplest setup using SimpleHTTPRequestHandler
to serve files from the current directory.
Basic Server Setup with HTTPServer
and SimpleHTTPRequestHandler
-
Import necessary modules:
from http.server import HTTPServer, SimpleHTTPRequestHandler
-
Define server address:
server_address = ('', 8000) # Host '', port 8000
Here,
''
indicates that the server will listen on all available network interfaces (both IPv4 and IPv6). Port8000
is a common port for development servers; you can change it if needed. -
Create the HTTP server instance:
httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
This line instantiates an
HTTPServer
object, binding it to the specified address and usingSimpleHTTPRequestHandler
to handle requests. -
Start the server:
print(f"Serving files from current directory at http://localhost:{server_address[1]}") httpd.serve_forever()
serve_forever()
starts the server and keeps it running indefinitely, listening for and handling incoming requests. The print statement provides a helpful message indicating where the server is accessible. -
Combine the code:
from http.server import HTTPServer, SimpleHTTPRequestHandler server_address = ('', 8000) httpd = HTTPServer(server_address, SimpleHTTPRequestHandler) print(f"Serving files from current directory at http://localhost:{server_address[1]}") httpd.serve_forever()
-
Run the server: Save this code as a Python file (e.g.,
simple_server.py
) and execute it from your terminal:python simple_server.py
You should see the message “Serving files from current directory at http://localhost:8000“.
-
Access the server: Open a web browser and navigate to
http://localhost:8000
. You should see a directory listing of the folder where you ran the Python script. If you have anindex.html
file in that directory, it will be displayed instead of the directory listing.
Serving Files and Directories
SimpleHTTPRequestHandler
automatically handles serving files and directory listings. When you request a URL, it maps the path part of the URL to a file or directory relative to the server’s starting directory.
-
File requests: If the URL corresponds to a file,
SimpleHTTPRequestHandler
will:- Check if the file exists and is readable.
- Determine the MIME type based on the file extension.
- Send the HTTP response headers, including
Content-type
,Content-Length
, andLast-Modified
. - Send the file content.
-
Directory requests: If the URL corresponds to a directory,
SimpleHTTPRequestHandler
will:- Look for
index.html
orindex.htm
in the directory. If found, it serves that index file. - If no index file is found, it generates an HTML listing of the directory contents.
- If
os.listdir()
fails (e.g., due to permissions), it returns a 404 error.
- Look for
Handling Different Request Types (GET, HEAD, POST)
SimpleHTTPRequestHandler
primarily implements do_GET()
and do_HEAD()
.
do_GET()
: Handles GET requests, which are used to retrieve resources. InSimpleHTTPRequestHandler
,do_GET()
is responsible for serving files and generating directory listings as described above.do_HEAD()
: Handles HEAD requests, which are similar to GET but only retrieve the headers, not the body of the response.SimpleHTTPRequestHandler
‘sdo_HEAD()
method sends the same headers asdo_GET()
would for the same resource.
SimpleHTTPRequestHandler
does not implement do_POST()
or other methods by default. If you need to handle POST requests or other HTTP methods, you would need to subclass SimpleHTTPRequestHandler
(or BaseHTTPRequestHandler
) and implement the corresponding do_METHOD()
methods. For instance, to handle POST requests, you would define a do_POST()
method in your custom handler.
Advanced Features and Considerations
While http.server
is simple to use, it also offers some advanced features and important considerations for more complex scenarios.
Threading with ThreadingHTTPServer
For handling multiple concurrent requests, especially in scenarios where you expect multiple clients to connect simultaneously, ThreadingHTTPServer
is highly recommended over HTTPServer
. As demonstrated earlier, switching to ThreadingHTTPServer
is as simple as changing the server class in your run
function. Threading allows the server to process requests concurrently, improving responsiveness and handling multiple connections more efficiently.
Customizing Request Handlers
For more specialized server behavior, you can create custom request handlers by subclassing BaseHTTPRequestHandler
or SimpleHTTPRequestHandler
. This allows you to override methods and add functionality tailored to your specific needs.
- Overriding
do_GET()
ordo_POST()
: You can modify the behavior for GET or POST requests. For example, you might want to serve dynamic content, implement API endpoints, or handle form data. - Handling different paths: You can customize how different URL paths are handled. For instance, you could set up specific paths to return different types of content or trigger specific actions on the server.
- Custom error handling: You can override
send_error()
to customize error responses. - Logging: You can customize logging behavior by overriding
log_message()
,log_request()
, andlog_error()
.
Here’s an example of a custom handler that responds with a simple message for all GET requests:
from http.server import HTTPServer, BaseHTTPRequestHandler
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(b"Hello, world! from custom handler")
def run(server_class=HTTPServer, handler_class=MyHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
if __name__ == '__main__':
run()
In this example, MyHandler
overrides do_GET()
to always send a 200 OK response with a plain text message, regardless of the requested path.
Security Notes and Production Use
It is crucial to reiterate that http.server
, especially SimpleHTTPRequestHandler
and CGIHTTPRequestHandler
, is not recommended for production use.
- Security vulnerabilities:
SimpleHTTPRequestHandler
follows symbolic links, which can allow access to files outside the intended directory.CGIHTTPRequestHandler
and CGI in general have known security risks if not carefully managed. - Lack of features:
http.server
lacks many features essential for production servers, such as robust security measures, performance optimizations, scalability, and advanced request handling capabilities. - Deprecation of CGI: The deprecation of
CGIHTTPRequestHandler
further underscores the move away from usinghttp.server
for dynamic content in favor of more modern and secure solutions.
For production web applications, consider using robust Python web frameworks like Flask, Django, or FastAPI, which offer comprehensive features, security, and performance.
Command-Line Interface of http.server
Python’s http.server
module can also be invoked directly from the command line, providing a quick way to start a simple HTTP server without writing any Python code.
Basic Usage: python -m http.server
To start a basic server serving files from the current directory on port 8000, simply run:
python -m http.server
This command is equivalent to running a Python script that uses HTTPServer
with SimpleHTTPRequestHandler
on port 8000. It’s incredibly convenient for quickly sharing files or testing web content locally.
Port, Bind Address, Directory, Protocol Options
The command-line interface offers several options to customize the server:
-
Port: To change the port, append the port number as an argument:
python -m http.server 9000
This will start the server on port 9000.
-
Bind Address: Use the
--bind
or-b
option to specify the address to bind to. For example, to bind to localhost only (IPv4):python -m http.server --bind 127.0.0.1
Or for IPv6 localhost:
python -m http.server --bind ::1
-
Directory: By default, the server serves files from the current directory. To serve files from a different directory, use the
--directory
or-d
option:python -m http.server --directory /tmp/
This will serve files from the
/tmp/
directory. -
Protocol: To specify the HTTP protocol version, use the
--protocol
or-p
option. For example, to use HTTP/1.1:python -m http.server --protocol HTTP/1.1
The default is HTTP/1.0.
CGI Support (and Deprecation Warning)
The command-line interface also supports enabling CGI with the --cgi
option:
python -m http.server --cgi
However, as mentioned earlier, CGI support and CGIHTTPRequestHandler
are deprecated and will be removed in Python 3.15. It is strongly advised against using CGI for new projects due to security and performance concerns. The --cgi
option and CGIHTTPRequestHandler
are primarily for maintaining legacy compatibility and should not be used for modern web development.
Conclusion
Python’s http.server
module provides a remarkably simple and effective way to set up basic HTTP servers. Whether through its Python classes or command-line interface, it offers a quick solution for serving files, testing web applications locally, and development tasks. While it’s not suitable for production environments due to security and feature limitations, its ease of use makes it an invaluable tool for developers and anyone needing a simple HTTP server for local or controlled environments. Remember to explore more robust and feature-rich web frameworks for production web applications.
References:
- Python
http.server
documentation
Python Logo
A web browser displaying content served by a simple HTTP server, illustrating the user interface for accessing server resources.