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(65537)
    117         if len(self.raw_requestline) > 65536:
    118             self.requestline = ''
    119             self.request_version = ''
    120             self.command = ''
    121             self.send_error(414)
    122             return
    123 
    124         if not self.parse_request(): # An error code has been sent, just exit
    125             return
    126 
    127         handler = ServerHandler(
    128             self.rfile, self.wfile, self.get_stderr(), self.get_environ()
    129         )
    130         handler.request_handler = self      # backpointer for logging
    131         handler.run(self.server.get_app())
    132 
    133 
    134 
    135 def demo_app(environ,start_response):
    136     from StringIO import StringIO
    137     stdout = StringIO()
    138     print >>stdout, "Hello world!"
    139     print >>stdout
    140     h = environ.items(); h.sort()
    141     for k,v in h:
    142         print >>stdout, k,'=', repr(v)
    143     start_response("200 OK", [('Content-Type','text/plain')])
    144     return [stdout.getvalue()]
    145 
    146 
    147 def make_server(
    148     host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
    149 ):
    150     """Create a new WSGI server listening on `host` and `port` for `app`"""
    151     server = server_class((host, port), handler_class)
    152     server.set_app(app)
    153     return server
    154 
    155 
    156 if __name__ == '__main__':
    157     httpd = make_server('', 8000, demo_app)
    158     sa = httpd.socket.getsockname()
    159     print "Serving HTTP on", sa[0], "port", sa[1], "..."
    160     import webbrowser
    161     webbrowser.open('http://localhost:8000/xyz?abc')
    162     httpd.handle_request()  # serve one request, then exit
    163     httpd.server_close()
    164