pythonhttp.server

how can I force specific mime types for python's http.server?


I have a bunch of files without extensions, so http.server is serving them all as application/octet-stream and this is causing problems...

Rather than giving them extensions, I would like a way to define a dictionary that would be filename -> mimetype. And then have GET requests to http.server look up the filename in that dictionary object, and set the Content-type header to its value.

Is there a way to do this?


Solution

  • You can use the extensions_map attribute of SimpleHTTPRequestHandler. When adding a mapping from the empty string to your preferred type, it will serve files without extension as that.

    from http.server import SimpleHTTPRequestHandler
    from socketserver import TCPServer
    
    
    def run():
        Handler = SimpleHTTPRequestHandler
        Handler.extensions_map = {'': 'text/plain'}
        with TCPServer(('', 8000), Handler) as httpd:
            httpd.serve_forever()
    
    
    if __name__ == '__main__':
        run()
    

    Here's the output of curl -I localhost:8000/myfile (with a corresponding file put in the appropriate place).

    HTTP/1.0 200 OK
    Server: SimpleHTTP/0.6 Python/3.11.7
    Date: Tue, 16 Jan 2024 23:35:28 GMT
    Content-type: text/plain
    Content-Length: 26
    Last-Modified: Tue, 16 Jan 2024 23:33:49 GMT
    

    If you want to serve different types and really map from individual file names to the types, it's somewhat more involved.

    You have to subclass and overwrite the behaviour of SimpleHTTPRequestHandler.guess_type. Start reading here.

    Should probably be something like this:

    def guess_type(self, path):
        from pathlib import Path
        path_name = Path(path).name
        return self.extensions_map.get(path_name, 'application/octet-stream')
    

    This is a sledgehammer job, and I suggest you don't use this example as is and do some sensible error handling instead. You get the idea.