Search code examples
pythongoogle-app-enginewsgipythonanywherebasehttpserver

Interfacing BaseHttpServer to WSGI in python


I am taking a python course where they use BaseHTTPServer. The code they start with is here

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class webServerHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            if self.path.endswith("/hello"):
                 self.send_response(200)
                 self.send_header('Content-type', 'text/html')
                 self.end_headers()
                 message = ""
                 message += "<html><body>Hello!</body></html>"
                 self.wfile.write(message)
                 print message
                 return
        except IOError:
            self.send_error(404, 'File Not Found: %s' % self.path)

def main():
    try:
        port = 8080
        server = HTTPServer(('', port), webServerHandler)
        print "Web Server running on port %s"  % port
        server.serve_forever()
    except KeyboardInterrupt:
        print " ^C entered, stopping web server...."
        server.socket.close()

if __name__ == '__main__':
    main()

I am using python anywhere and there the only possibility to get an application onto the internet is to use an wsgi interface.

A configuration file for the wsgi interface looks like this:

import sys

path = '<path to app>'
if path not in sys.path:
    sys.path.append(path)

from app import application

application could be something like this:

def application(environ, start_response):
    if environ.get('PATH_INFO') == '/':
        status = '200 OK'
        content = HELLO_WORLD
    else:
        status = '404 NOT FOUND'
        content = 'Page not found.'
    response_headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(content)))]
    start_response(status, response_headers)
    yield content.encode('utf8')

HELLO_WORLD would be a string with html content.

I cannot just point to port 8080 as in the example. In order to use python anywhere I do have to interface both. I reckoned it could be possible that the wsgi is derived from BaseHTTPServer so it might be possible to interface them and to use my course on pythonanywhere.com

It is clear I have to get rid in the code in the main function and use the application function instead. But I am not exactly getting how this works. I get a callback (start_response) which I call and then I yield the content? How can I combine this with the webServerHandler class?

If this would be possible it should in theory work as well for the google app engine. I found a very complex example here where BaseHTTPServer is used but this is too complex for me yet.

Is it possible to do this and if yes could someone give me a hint how to do this and provide me with some basic start code?


Solution

  • So WSGI is a specification that defines an interface between a request and a webapp. ie. when it receives a http request, it will pass it along to the webapp in a standardized way as described in the specification (eg: it must set this environment variable, it must pass this argument, it must make this call etc).

    On the other hand, BaseHTTPServer both defines an interface and also has code that actually serves web requests.

    • This is a little used interface that is implemented almost exclusively by SimpleHTTPServer from the python2 standard library (or http.server in python3), and the server is not intended for anything production-ready.
    • This is because SimpleHTTPServer was designed mainly for developing locally. For example, it helps you get past js cross origin request problems when testing on localhost.

    Nowadays, WSGI has become the de facto standard for python webapps, and so most websites written in python separate out the server / interface-y functionality that receives and implements the WSGI requirements from the webapp-y stuff.

    In your code, you have a single piece of code that does both the "webapp-y" stuff and also the "process the http request / interface-y" stuff. This is not wrong, and is great for getting some basic understanding of how servers process http requests etc.

    So my suggestion would be:

    1. if your class is going to start using any python webapp frameworks soon anywahs, (eg: django, flask, , bottle, web2py, cherrypy etc), then you could potentially just wait till then to use pythonanywhere.
    2. if your class is focused on digging into the nitty gritty of servers, you could refactor out the "webapp-y" layer from your code, and just use the "webapp-y" layer on PythonAnywhere. Locally, you would start the "server/interface-y" stuff that then imports your "webapp-y" to generate a response. If you successfully do this, then congrats! You have (kind of) just written a server that supports WSGI.