minghua
minghua

Reputation: 6583

Python HTTP Server Serves Two Paths Using Different Kinds of Handlers

From other SO posts, it's clear how to serve content from a specific directory, and how to map an incoming path to different do_GET handlers.

To expand on the second question in a way relating to the first, how do you map paths to different kinds of handlers? Specifically, I'd like to map one path to do_GET handler, and another to just serving the content from a specific directory.

If it is not possible, what's the easier way to serve the two different kinds of contents? I know the two could be run on the server in two threads each serving a different port, that's not very neat.

Upvotes: 3

Views: 4599

Answers (1)

minghua
minghua

Reputation: 6583

I've got an answer by tracking the code from the first reference question answered by Jaymon, and incorporating the code from the second reference question.

The sample follows. It serves content on the local machine from the directory web/ to the URL base path /file/, and handles requests with URL base path /api in the user-supplied method do_GET() itself. Initially the code was derived from a sample on the web by Dr. Axel Rauschmayer.

#!/usr/bin/env python
# https://2ality.com/2014/06/simple-http-server.html
# https://stackoverflow.com/questions/39801718/how-to-run-a-http-server-which-serves-a-specific-path

from SimpleHTTPServer import SimpleHTTPRequestHandler
from BaseHTTPServer import HTTPServer as BaseHTTPServer
import os

PORT = 8000

class HTTPHandler(SimpleHTTPRequestHandler):
    """This handler uses server.base_path instead of always using os.getcwd()"""
    def translate_path(self, path):
        if path.startswith(self.server.base_url_path):
            path = path[len(self.server.base_url_path):]
            if path == '':
                path = '/'
        else:
            #path = '/'
            return None
        path = SimpleHTTPRequestHandler.translate_path(self, path)
        relpath = os.path.relpath(path, os.getcwd())
        fullpath = os.path.join(self.server.base_local_path, relpath)
        return fullpath
    def do_GET(self):
        path = self.path
        if (type(path) is str or type(path) is unicode) and path.startswith('/api'):
            # call local handler
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            # Send the html message
            self.wfile.write("<b> Hello World !</b>")
            self.wfile.close()
            return
        elif (type(path) is str or type(path) is unicode) and path.startswith(self.server.base_url_path):
            return SimpleHTTPRequestHandler.do_GET(self)
        elif (type(path) is str or type(path) is unicode) and path.startswith('/'):
            self.send_response(441)
            self.end_headers()
            self.wfile.close()
            return
        else:
            self.send_response(442)
            self.end_headers()
            self.wfile.close()
            return

Handler = HTTPHandler
Handler.extensions_map.update({
    '.webapp': 'application/x-web-app-manifest+json',
});

class HTTPServer(BaseHTTPServer):
    """The main server, you pass in base_path which is the path you want to serve requests from"""
    def __init__(self, base_local_path, base_url_path, server_address, RequestHandlerClass=HTTPHandler):
        self.base_local_path = base_local_path
        self.base_url_path = base_url_path
        BaseHTTPServer.__init__(self, server_address, RequestHandlerClass)

web_dir = os.path.join(os.path.dirname(__file__), 'web')
httpd = HTTPServer(web_dir, '/file', ("", PORT))

print "Serving at port", PORT
httpd.serve_forever()

Upvotes: 3

Related Questions