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