Home | History | Annotate | Download | only in wsgiref
      1 """BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
      2 
      3 This is both an example of how WSGI can be implemented, and a basis for running
      4 simple web applications on a local machine, such as might be done when testing
      5 or debugging an application.  It has not been reviewed for security issues,
      6 however, and we strongly recommend that you use a "real" web server for
      7 production use.
      8 
      9 For example usage, see the 'if __name__=="__main__"' block at the end of the
     10 module.  See also the BaseHTTPServer module docs for other API information.
     11 """
     12 
     13 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
     14 import urllib, sys
     15 from wsgiref.handlers import SimpleHandler
     16 
     17 __version__ = "0.1"
     18 __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
     19 
     20 
     21 server_version = "WSGIServer/" + __version__
     22 sys_version = "Python/" + sys.version.split()[0]
     23 software_version = server_version + ' ' + sys_version
     24 
     25 
     26 class ServerHandler(SimpleHandler):
     27 
     28     server_software = software_version
     29 
     30     def close(self):
     31         try:
     32             self.request_handler.log_request(
     33                 self.status.split(' ',1)[0], self.bytes_sent
     34             )
     35         finally:
     36             SimpleHandler.close(self)
     37 
     38 
     39 
     40 class WSGIServer(HTTPServer):
     41 
     42     """BaseHTTPServer that implements the Python WSGI protocol"""
     43 
     44     application = None
     45 
     46     def server_bind(self):
     47         """Override server_bind to store the server name."""
     48         HTTPServer.server_bind(self)
     49         self.setup_environ()
     50 
     51     def setup_environ(self):
     52         # Set up base environment
     53         env = self.base_environ = {}
     54         env['SERVER_NAME'] = self.server_name
     55         env['GATEWAY_INTERFACE'] = 'CGI/1.1'
     56         env['SERVER_PORT'] = str(self.server_port)
     57         env['REMOTE_HOST']=''
     58         env['CONTENT_LENGTH']=''
     59         env['SCRIPT_NAME'] = ''
     60 
     61     def get_app(self):
     62         return self.application
     63 
     64     def set_app(self,application):
     65         self.application = application
     66 
     67 
     68 
     69 class WSGIRequestHandler(BaseHTTPRequestHandler):
     70 
     71     server_version = "WSGIServer/" + __version__
     72 
     73     def get_environ(self):
     74         env = self.server.base_environ.copy()
     75         env['SERVER_PROTOCOL'] = self.request_version
     76         env['REQUEST_METHOD'] = self.command
     77         if '?' in self.path:
     78             path,query = self.path.split('?',1)
     79         else:
     80             path,query = self.path,''
     81 
     82         env['PATH_INFO'] = urllib.unquote(path)
     83         env['QUERY_STRING'] = query
     84 
     85         host = self.address_string()
     86         if host != self.client_address[0]:
     87             env['REMOTE_HOST'] = host
     88         env['REMOTE_ADDR'] = self.client_address[0]
     89 
     90         if self.headers.typeheader is None:
     91             env['CONTENT_TYPE'] = self.headers.type
     92         else:
     93             env['CONTENT_TYPE'] = self.headers.typeheader
     94 
     95         length = self.headers.getheader('content-length')
     96         if length:
     97             env['CONTENT_LENGTH'] = length
     98 
     99         for h in self.headers.headers:
    100             k,v = h.split(':',1)
    101             k=k.replace('-','_').upper(); v=v.strip()
    102             if k in env:
    103                 continue                    # skip content length, type,etc.
    104             if 'HTTP_'+k in env:
    105                 env['HTTP_'+k] += ','+v     # comma-separate multiple headers
    106             else:
    107                 env['HTTP_'+k] = v
    108         return env
    109 
    110     def get_stderr(self):
    111         return sys.stderr
    112 
    113     def handle(self):
    114         """Handle a single HTTP request"""
    115 
    116         self.raw_requestline = self.rfile.readline()
    117         if not self.parse_request(): # An error code has been sent, just exit
    118             return
    119 
    120         handler = ServerHandler(
    121             self.rfile, self.wfile, self.get_stderr(), self.get_environ()
    122         )
    123         handler.request_handler = self      # backpointer for logging
    124         handler.run(self.server.get_app())
    125 
    126 
    127 
    128 def demo_app(environ,start_response):
    129     from StringIO import StringIO
    130     stdout = StringIO()
    131     print >>stdout, "Hello world!"
    132     print >>stdout
    133     h = environ.items(); h.sort()
    134     for k,v in h:
    135         print >>stdout, k,'=', repr(v)
    136     start_response("200 OK", [('Content-Type','text/plain')])
    137     return [stdout.getvalue()]
    138 
    139 
    140 def make_server(
    141     host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
    142 ):
    143     """Create a new WSGI server listening on `host` and `port` for `app`"""
    144     server = server_class((host, port), handler_class)
    145     server.set_app(app)
    146     return server
    147 
    148 
    149 if __name__ == '__main__':
    150     httpd = make_server('', 8000, demo_app)
    151     sa = httpd.socket.getsockname()
    152     print "Serving HTTP on", sa[0], "port", sa[1], "..."
    153     import webbrowser
    154     webbrowser.open('http://localhost:8000/xyz?abc')
    155     httpd.handle_request()  # serve one request, then exit
    156