xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/wsgiref/handlers.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Base classes for server/gateway implementations"""
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Workerfrom .util import FileWrapper, guess_scheme, is_hop_by_hop
4*cda5da8dSAndroid Build Coastguard Workerfrom .headers import Headers
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard Workerimport sys, os, time
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Worker__all__ = [
9*cda5da8dSAndroid Build Coastguard Worker    'BaseHandler', 'SimpleHandler', 'BaseCGIHandler', 'CGIHandler',
10*cda5da8dSAndroid Build Coastguard Worker    'IISCGIHandler', 'read_environ'
11*cda5da8dSAndroid Build Coastguard Worker]
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard Worker# Weekday and month names for HTTP date/time formatting; always English!
14*cda5da8dSAndroid Build Coastguard Worker_weekdayname = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
15*cda5da8dSAndroid Build Coastguard Worker_monthname = [None, # Dummy so we can use 1-based month numbers
16*cda5da8dSAndroid Build Coastguard Worker              "Jan", "Feb", "Mar", "Apr", "May", "Jun",
17*cda5da8dSAndroid Build Coastguard Worker              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Workerdef format_date_time(timestamp):
20*cda5da8dSAndroid Build Coastguard Worker    year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
21*cda5da8dSAndroid Build Coastguard Worker    return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
22*cda5da8dSAndroid Build Coastguard Worker        _weekdayname[wd], day, _monthname[month], year, hh, mm, ss
23*cda5da8dSAndroid Build Coastguard Worker    )
24*cda5da8dSAndroid Build Coastguard Worker
25*cda5da8dSAndroid Build Coastguard Worker_is_request = {
26*cda5da8dSAndroid Build Coastguard Worker    'SCRIPT_NAME', 'PATH_INFO', 'QUERY_STRING', 'REQUEST_METHOD', 'AUTH_TYPE',
27*cda5da8dSAndroid Build Coastguard Worker    'CONTENT_TYPE', 'CONTENT_LENGTH', 'HTTPS', 'REMOTE_USER', 'REMOTE_IDENT',
28*cda5da8dSAndroid Build Coastguard Worker}.__contains__
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard Workerdef _needs_transcode(k):
31*cda5da8dSAndroid Build Coastguard Worker    return _is_request(k) or k.startswith('HTTP_') or k.startswith('SSL_') \
32*cda5da8dSAndroid Build Coastguard Worker        or (k.startswith('REDIRECT_') and _needs_transcode(k[9:]))
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard Workerdef read_environ():
35*cda5da8dSAndroid Build Coastguard Worker    """Read environment, fixing HTTP variables"""
36*cda5da8dSAndroid Build Coastguard Worker    enc = sys.getfilesystemencoding()
37*cda5da8dSAndroid Build Coastguard Worker    esc = 'surrogateescape'
38*cda5da8dSAndroid Build Coastguard Worker    try:
39*cda5da8dSAndroid Build Coastguard Worker        ''.encode('utf-8', esc)
40*cda5da8dSAndroid Build Coastguard Worker    except LookupError:
41*cda5da8dSAndroid Build Coastguard Worker        esc = 'replace'
42*cda5da8dSAndroid Build Coastguard Worker    environ = {}
43*cda5da8dSAndroid Build Coastguard Worker
44*cda5da8dSAndroid Build Coastguard Worker    # Take the basic environment from native-unicode os.environ. Attempt to
45*cda5da8dSAndroid Build Coastguard Worker    # fix up the variables that come from the HTTP request to compensate for
46*cda5da8dSAndroid Build Coastguard Worker    # the bytes->unicode decoding step that will already have taken place.
47*cda5da8dSAndroid Build Coastguard Worker    for k, v in os.environ.items():
48*cda5da8dSAndroid Build Coastguard Worker        if _needs_transcode(k):
49*cda5da8dSAndroid Build Coastguard Worker
50*cda5da8dSAndroid Build Coastguard Worker            # On win32, the os.environ is natively Unicode. Different servers
51*cda5da8dSAndroid Build Coastguard Worker            # decode the request bytes using different encodings.
52*cda5da8dSAndroid Build Coastguard Worker            if sys.platform == 'win32':
53*cda5da8dSAndroid Build Coastguard Worker                software = os.environ.get('SERVER_SOFTWARE', '').lower()
54*cda5da8dSAndroid Build Coastguard Worker
55*cda5da8dSAndroid Build Coastguard Worker                # On IIS, the HTTP request will be decoded as UTF-8 as long
56*cda5da8dSAndroid Build Coastguard Worker                # as the input is a valid UTF-8 sequence. Otherwise it is
57*cda5da8dSAndroid Build Coastguard Worker                # decoded using the system code page (mbcs), with no way to
58*cda5da8dSAndroid Build Coastguard Worker                # detect this has happened. Because UTF-8 is the more likely
59*cda5da8dSAndroid Build Coastguard Worker                # encoding, and mbcs is inherently unreliable (an mbcs string
60*cda5da8dSAndroid Build Coastguard Worker                # that happens to be valid UTF-8 will not be decoded as mbcs)
61*cda5da8dSAndroid Build Coastguard Worker                # always recreate the original bytes as UTF-8.
62*cda5da8dSAndroid Build Coastguard Worker                if software.startswith('microsoft-iis/'):
63*cda5da8dSAndroid Build Coastguard Worker                    v = v.encode('utf-8').decode('iso-8859-1')
64*cda5da8dSAndroid Build Coastguard Worker
65*cda5da8dSAndroid Build Coastguard Worker                # Apache mod_cgi writes bytes-as-unicode (as if ISO-8859-1) direct
66*cda5da8dSAndroid Build Coastguard Worker                # to the Unicode environ. No modification needed.
67*cda5da8dSAndroid Build Coastguard Worker                elif software.startswith('apache/'):
68*cda5da8dSAndroid Build Coastguard Worker                    pass
69*cda5da8dSAndroid Build Coastguard Worker
70*cda5da8dSAndroid Build Coastguard Worker                # Python 3's http.server.CGIHTTPRequestHandler decodes
71*cda5da8dSAndroid Build Coastguard Worker                # using the urllib.unquote default of UTF-8, amongst other
72*cda5da8dSAndroid Build Coastguard Worker                # issues.
73*cda5da8dSAndroid Build Coastguard Worker                elif (
74*cda5da8dSAndroid Build Coastguard Worker                    software.startswith('simplehttp/')
75*cda5da8dSAndroid Build Coastguard Worker                    and 'python/3' in software
76*cda5da8dSAndroid Build Coastguard Worker                ):
77*cda5da8dSAndroid Build Coastguard Worker                    v = v.encode('utf-8').decode('iso-8859-1')
78*cda5da8dSAndroid Build Coastguard Worker
79*cda5da8dSAndroid Build Coastguard Worker                # For other servers, guess that they have written bytes to
80*cda5da8dSAndroid Build Coastguard Worker                # the environ using stdio byte-oriented interfaces, ending up
81*cda5da8dSAndroid Build Coastguard Worker                # with the system code page.
82*cda5da8dSAndroid Build Coastguard Worker                else:
83*cda5da8dSAndroid Build Coastguard Worker                    v = v.encode(enc, 'replace').decode('iso-8859-1')
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Worker            # Recover bytes from unicode environ, using surrogate escapes
86*cda5da8dSAndroid Build Coastguard Worker            # where available (Python 3.1+).
87*cda5da8dSAndroid Build Coastguard Worker            else:
88*cda5da8dSAndroid Build Coastguard Worker                v = v.encode(enc, esc).decode('iso-8859-1')
89*cda5da8dSAndroid Build Coastguard Worker
90*cda5da8dSAndroid Build Coastguard Worker        environ[k] = v
91*cda5da8dSAndroid Build Coastguard Worker    return environ
92*cda5da8dSAndroid Build Coastguard Worker
93*cda5da8dSAndroid Build Coastguard Worker
94*cda5da8dSAndroid Build Coastguard Workerclass BaseHandler:
95*cda5da8dSAndroid Build Coastguard Worker    """Manage the invocation of a WSGI application"""
96*cda5da8dSAndroid Build Coastguard Worker
97*cda5da8dSAndroid Build Coastguard Worker    # Configuration parameters; can override per-subclass or per-instance
98*cda5da8dSAndroid Build Coastguard Worker    wsgi_version = (1,0)
99*cda5da8dSAndroid Build Coastguard Worker    wsgi_multithread = True
100*cda5da8dSAndroid Build Coastguard Worker    wsgi_multiprocess = True
101*cda5da8dSAndroid Build Coastguard Worker    wsgi_run_once = False
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Worker    origin_server = True    # We are transmitting direct to client
104*cda5da8dSAndroid Build Coastguard Worker    http_version  = "1.0"   # Version that should be used for response
105*cda5da8dSAndroid Build Coastguard Worker    server_software = None  # String name of server software, if any
106*cda5da8dSAndroid Build Coastguard Worker
107*cda5da8dSAndroid Build Coastguard Worker    # os_environ is used to supply configuration from the OS environment:
108*cda5da8dSAndroid Build Coastguard Worker    # by default it's a copy of 'os.environ' as of import time, but you can
109*cda5da8dSAndroid Build Coastguard Worker    # override this in e.g. your __init__ method.
110*cda5da8dSAndroid Build Coastguard Worker    os_environ= read_environ()
111*cda5da8dSAndroid Build Coastguard Worker
112*cda5da8dSAndroid Build Coastguard Worker    # Collaborator classes
113*cda5da8dSAndroid Build Coastguard Worker    wsgi_file_wrapper = FileWrapper     # set to None to disable
114*cda5da8dSAndroid Build Coastguard Worker    headers_class = Headers             # must be a Headers-like class
115*cda5da8dSAndroid Build Coastguard Worker
116*cda5da8dSAndroid Build Coastguard Worker    # Error handling (also per-subclass or per-instance)
117*cda5da8dSAndroid Build Coastguard Worker    traceback_limit = None  # Print entire traceback to self.get_stderr()
118*cda5da8dSAndroid Build Coastguard Worker    error_status = "500 Internal Server Error"
119*cda5da8dSAndroid Build Coastguard Worker    error_headers = [('Content-Type','text/plain')]
120*cda5da8dSAndroid Build Coastguard Worker    error_body = b"A server error occurred.  Please contact the administrator."
121*cda5da8dSAndroid Build Coastguard Worker
122*cda5da8dSAndroid Build Coastguard Worker    # State variables (don't mess with these)
123*cda5da8dSAndroid Build Coastguard Worker    status = result = None
124*cda5da8dSAndroid Build Coastguard Worker    headers_sent = False
125*cda5da8dSAndroid Build Coastguard Worker    headers = None
126*cda5da8dSAndroid Build Coastguard Worker    bytes_sent = 0
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker    def run(self, application):
129*cda5da8dSAndroid Build Coastguard Worker        """Invoke the application"""
130*cda5da8dSAndroid Build Coastguard Worker        # Note to self: don't move the close()!  Asynchronous servers shouldn't
131*cda5da8dSAndroid Build Coastguard Worker        # call close() from finish_response(), so if you close() anywhere but
132*cda5da8dSAndroid Build Coastguard Worker        # the double-error branch here, you'll break asynchronous servers by
133*cda5da8dSAndroid Build Coastguard Worker        # prematurely closing.  Async servers must return from 'run()' without
134*cda5da8dSAndroid Build Coastguard Worker        # closing if there might still be output to iterate over.
135*cda5da8dSAndroid Build Coastguard Worker        try:
136*cda5da8dSAndroid Build Coastguard Worker            self.setup_environ()
137*cda5da8dSAndroid Build Coastguard Worker            self.result = application(self.environ, self.start_response)
138*cda5da8dSAndroid Build Coastguard Worker            self.finish_response()
139*cda5da8dSAndroid Build Coastguard Worker        except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
140*cda5da8dSAndroid Build Coastguard Worker            # We expect the client to close the connection abruptly from time
141*cda5da8dSAndroid Build Coastguard Worker            # to time.
142*cda5da8dSAndroid Build Coastguard Worker            return
143*cda5da8dSAndroid Build Coastguard Worker        except:
144*cda5da8dSAndroid Build Coastguard Worker            try:
145*cda5da8dSAndroid Build Coastguard Worker                self.handle_error()
146*cda5da8dSAndroid Build Coastguard Worker            except:
147*cda5da8dSAndroid Build Coastguard Worker                # If we get an error handling an error, just give up already!
148*cda5da8dSAndroid Build Coastguard Worker                self.close()
149*cda5da8dSAndroid Build Coastguard Worker                raise   # ...and let the actual server figure it out.
150*cda5da8dSAndroid Build Coastguard Worker
151*cda5da8dSAndroid Build Coastguard Worker
152*cda5da8dSAndroid Build Coastguard Worker    def setup_environ(self):
153*cda5da8dSAndroid Build Coastguard Worker        """Set up the environment for one request"""
154*cda5da8dSAndroid Build Coastguard Worker
155*cda5da8dSAndroid Build Coastguard Worker        env = self.environ = self.os_environ.copy()
156*cda5da8dSAndroid Build Coastguard Worker        self.add_cgi_vars()
157*cda5da8dSAndroid Build Coastguard Worker
158*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.input']        = self.get_stdin()
159*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.errors']       = self.get_stderr()
160*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.version']      = self.wsgi_version
161*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.run_once']     = self.wsgi_run_once
162*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.url_scheme']   = self.get_scheme()
163*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.multithread']  = self.wsgi_multithread
164*cda5da8dSAndroid Build Coastguard Worker        env['wsgi.multiprocess'] = self.wsgi_multiprocess
165*cda5da8dSAndroid Build Coastguard Worker
166*cda5da8dSAndroid Build Coastguard Worker        if self.wsgi_file_wrapper is not None:
167*cda5da8dSAndroid Build Coastguard Worker            env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker        if self.origin_server and self.server_software:
170*cda5da8dSAndroid Build Coastguard Worker            env.setdefault('SERVER_SOFTWARE',self.server_software)
171*cda5da8dSAndroid Build Coastguard Worker
172*cda5da8dSAndroid Build Coastguard Worker
173*cda5da8dSAndroid Build Coastguard Worker    def finish_response(self):
174*cda5da8dSAndroid Build Coastguard Worker        """Send any iterable data, then close self and the iterable
175*cda5da8dSAndroid Build Coastguard Worker
176*cda5da8dSAndroid Build Coastguard Worker        Subclasses intended for use in asynchronous servers will
177*cda5da8dSAndroid Build Coastguard Worker        want to redefine this method, such that it sets up callbacks
178*cda5da8dSAndroid Build Coastguard Worker        in the event loop to iterate over the data, and to call
179*cda5da8dSAndroid Build Coastguard Worker        'self.close()' once the response is finished.
180*cda5da8dSAndroid Build Coastguard Worker        """
181*cda5da8dSAndroid Build Coastguard Worker        try:
182*cda5da8dSAndroid Build Coastguard Worker            if not self.result_is_file() or not self.sendfile():
183*cda5da8dSAndroid Build Coastguard Worker                for data in self.result:
184*cda5da8dSAndroid Build Coastguard Worker                    self.write(data)
185*cda5da8dSAndroid Build Coastguard Worker                self.finish_content()
186*cda5da8dSAndroid Build Coastguard Worker        except:
187*cda5da8dSAndroid Build Coastguard Worker            # Call close() on the iterable returned by the WSGI application
188*cda5da8dSAndroid Build Coastguard Worker            # in case of an exception.
189*cda5da8dSAndroid Build Coastguard Worker            if hasattr(self.result, 'close'):
190*cda5da8dSAndroid Build Coastguard Worker                self.result.close()
191*cda5da8dSAndroid Build Coastguard Worker            raise
192*cda5da8dSAndroid Build Coastguard Worker        else:
193*cda5da8dSAndroid Build Coastguard Worker            # We only call close() when no exception is raised, because it
194*cda5da8dSAndroid Build Coastguard Worker            # will set status, result, headers, and environ fields to None.
195*cda5da8dSAndroid Build Coastguard Worker            # See bpo-29183 for more details.
196*cda5da8dSAndroid Build Coastguard Worker            self.close()
197*cda5da8dSAndroid Build Coastguard Worker
198*cda5da8dSAndroid Build Coastguard Worker
199*cda5da8dSAndroid Build Coastguard Worker    def get_scheme(self):
200*cda5da8dSAndroid Build Coastguard Worker        """Return the URL scheme being used"""
201*cda5da8dSAndroid Build Coastguard Worker        return guess_scheme(self.environ)
202*cda5da8dSAndroid Build Coastguard Worker
203*cda5da8dSAndroid Build Coastguard Worker
204*cda5da8dSAndroid Build Coastguard Worker    def set_content_length(self):
205*cda5da8dSAndroid Build Coastguard Worker        """Compute Content-Length or switch to chunked encoding if possible"""
206*cda5da8dSAndroid Build Coastguard Worker        try:
207*cda5da8dSAndroid Build Coastguard Worker            blocks = len(self.result)
208*cda5da8dSAndroid Build Coastguard Worker        except (TypeError,AttributeError,NotImplementedError):
209*cda5da8dSAndroid Build Coastguard Worker            pass
210*cda5da8dSAndroid Build Coastguard Worker        else:
211*cda5da8dSAndroid Build Coastguard Worker            if blocks==1:
212*cda5da8dSAndroid Build Coastguard Worker                self.headers['Content-Length'] = str(self.bytes_sent)
213*cda5da8dSAndroid Build Coastguard Worker                return
214*cda5da8dSAndroid Build Coastguard Worker        # XXX Try for chunked encoding if origin server and client is 1.1
215*cda5da8dSAndroid Build Coastguard Worker
216*cda5da8dSAndroid Build Coastguard Worker
217*cda5da8dSAndroid Build Coastguard Worker    def cleanup_headers(self):
218*cda5da8dSAndroid Build Coastguard Worker        """Make any necessary header changes or defaults
219*cda5da8dSAndroid Build Coastguard Worker
220*cda5da8dSAndroid Build Coastguard Worker        Subclasses can extend this to add other defaults.
221*cda5da8dSAndroid Build Coastguard Worker        """
222*cda5da8dSAndroid Build Coastguard Worker        if 'Content-Length' not in self.headers:
223*cda5da8dSAndroid Build Coastguard Worker            self.set_content_length()
224*cda5da8dSAndroid Build Coastguard Worker
225*cda5da8dSAndroid Build Coastguard Worker    def start_response(self, status, headers,exc_info=None):
226*cda5da8dSAndroid Build Coastguard Worker        """'start_response()' callable as specified by PEP 3333"""
227*cda5da8dSAndroid Build Coastguard Worker
228*cda5da8dSAndroid Build Coastguard Worker        if exc_info:
229*cda5da8dSAndroid Build Coastguard Worker            try:
230*cda5da8dSAndroid Build Coastguard Worker                if self.headers_sent:
231*cda5da8dSAndroid Build Coastguard Worker                    raise
232*cda5da8dSAndroid Build Coastguard Worker            finally:
233*cda5da8dSAndroid Build Coastguard Worker                exc_info = None        # avoid dangling circular ref
234*cda5da8dSAndroid Build Coastguard Worker        elif self.headers is not None:
235*cda5da8dSAndroid Build Coastguard Worker            raise AssertionError("Headers already set!")
236*cda5da8dSAndroid Build Coastguard Worker
237*cda5da8dSAndroid Build Coastguard Worker        self.status = status
238*cda5da8dSAndroid Build Coastguard Worker        self.headers = self.headers_class(headers)
239*cda5da8dSAndroid Build Coastguard Worker        status = self._convert_string_type(status, "Status")
240*cda5da8dSAndroid Build Coastguard Worker        assert len(status)>=4,"Status must be at least 4 characters"
241*cda5da8dSAndroid Build Coastguard Worker        assert status[:3].isdigit(), "Status message must begin w/3-digit code"
242*cda5da8dSAndroid Build Coastguard Worker        assert status[3]==" ", "Status message must have a space after code"
243*cda5da8dSAndroid Build Coastguard Worker
244*cda5da8dSAndroid Build Coastguard Worker        if __debug__:
245*cda5da8dSAndroid Build Coastguard Worker            for name, val in headers:
246*cda5da8dSAndroid Build Coastguard Worker                name = self._convert_string_type(name, "Header name")
247*cda5da8dSAndroid Build Coastguard Worker                val = self._convert_string_type(val, "Header value")
248*cda5da8dSAndroid Build Coastguard Worker                assert not is_hop_by_hop(name),\
249*cda5da8dSAndroid Build Coastguard Worker                       f"Hop-by-hop header, '{name}: {val}', not allowed"
250*cda5da8dSAndroid Build Coastguard Worker
251*cda5da8dSAndroid Build Coastguard Worker        return self.write
252*cda5da8dSAndroid Build Coastguard Worker
253*cda5da8dSAndroid Build Coastguard Worker    def _convert_string_type(self, value, title):
254*cda5da8dSAndroid Build Coastguard Worker        """Convert/check value type."""
255*cda5da8dSAndroid Build Coastguard Worker        if type(value) is str:
256*cda5da8dSAndroid Build Coastguard Worker            return value
257*cda5da8dSAndroid Build Coastguard Worker        raise AssertionError(
258*cda5da8dSAndroid Build Coastguard Worker            "{0} must be of type str (got {1})".format(title, repr(value))
259*cda5da8dSAndroid Build Coastguard Worker        )
260*cda5da8dSAndroid Build Coastguard Worker
261*cda5da8dSAndroid Build Coastguard Worker    def send_preamble(self):
262*cda5da8dSAndroid Build Coastguard Worker        """Transmit version/status/date/server, via self._write()"""
263*cda5da8dSAndroid Build Coastguard Worker        if self.origin_server:
264*cda5da8dSAndroid Build Coastguard Worker            if self.client_is_modern():
265*cda5da8dSAndroid Build Coastguard Worker                self._write(('HTTP/%s %s\r\n' % (self.http_version,self.status)).encode('iso-8859-1'))
266*cda5da8dSAndroid Build Coastguard Worker                if 'Date' not in self.headers:
267*cda5da8dSAndroid Build Coastguard Worker                    self._write(
268*cda5da8dSAndroid Build Coastguard Worker                        ('Date: %s\r\n' % format_date_time(time.time())).encode('iso-8859-1')
269*cda5da8dSAndroid Build Coastguard Worker                    )
270*cda5da8dSAndroid Build Coastguard Worker                if self.server_software and 'Server' not in self.headers:
271*cda5da8dSAndroid Build Coastguard Worker                    self._write(('Server: %s\r\n' % self.server_software).encode('iso-8859-1'))
272*cda5da8dSAndroid Build Coastguard Worker        else:
273*cda5da8dSAndroid Build Coastguard Worker            self._write(('Status: %s\r\n' % self.status).encode('iso-8859-1'))
274*cda5da8dSAndroid Build Coastguard Worker
275*cda5da8dSAndroid Build Coastguard Worker    def write(self, data):
276*cda5da8dSAndroid Build Coastguard Worker        """'write()' callable as specified by PEP 3333"""
277*cda5da8dSAndroid Build Coastguard Worker
278*cda5da8dSAndroid Build Coastguard Worker        assert type(data) is bytes, \
279*cda5da8dSAndroid Build Coastguard Worker            "write() argument must be a bytes instance"
280*cda5da8dSAndroid Build Coastguard Worker
281*cda5da8dSAndroid Build Coastguard Worker        if not self.status:
282*cda5da8dSAndroid Build Coastguard Worker            raise AssertionError("write() before start_response()")
283*cda5da8dSAndroid Build Coastguard Worker
284*cda5da8dSAndroid Build Coastguard Worker        elif not self.headers_sent:
285*cda5da8dSAndroid Build Coastguard Worker            # Before the first output, send the stored headers
286*cda5da8dSAndroid Build Coastguard Worker            self.bytes_sent = len(data)    # make sure we know content-length
287*cda5da8dSAndroid Build Coastguard Worker            self.send_headers()
288*cda5da8dSAndroid Build Coastguard Worker        else:
289*cda5da8dSAndroid Build Coastguard Worker            self.bytes_sent += len(data)
290*cda5da8dSAndroid Build Coastguard Worker
291*cda5da8dSAndroid Build Coastguard Worker        # XXX check Content-Length and truncate if too many bytes written?
292*cda5da8dSAndroid Build Coastguard Worker        self._write(data)
293*cda5da8dSAndroid Build Coastguard Worker        self._flush()
294*cda5da8dSAndroid Build Coastguard Worker
295*cda5da8dSAndroid Build Coastguard Worker
296*cda5da8dSAndroid Build Coastguard Worker    def sendfile(self):
297*cda5da8dSAndroid Build Coastguard Worker        """Platform-specific file transmission
298*cda5da8dSAndroid Build Coastguard Worker
299*cda5da8dSAndroid Build Coastguard Worker        Override this method in subclasses to support platform-specific
300*cda5da8dSAndroid Build Coastguard Worker        file transmission.  It is only called if the application's
301*cda5da8dSAndroid Build Coastguard Worker        return iterable ('self.result') is an instance of
302*cda5da8dSAndroid Build Coastguard Worker        'self.wsgi_file_wrapper'.
303*cda5da8dSAndroid Build Coastguard Worker
304*cda5da8dSAndroid Build Coastguard Worker        This method should return a true value if it was able to actually
305*cda5da8dSAndroid Build Coastguard Worker        transmit the wrapped file-like object using a platform-specific
306*cda5da8dSAndroid Build Coastguard Worker        approach.  It should return a false value if normal iteration
307*cda5da8dSAndroid Build Coastguard Worker        should be used instead.  An exception can be raised to indicate
308*cda5da8dSAndroid Build Coastguard Worker        that transmission was attempted, but failed.
309*cda5da8dSAndroid Build Coastguard Worker
310*cda5da8dSAndroid Build Coastguard Worker        NOTE: this method should call 'self.send_headers()' if
311*cda5da8dSAndroid Build Coastguard Worker        'self.headers_sent' is false and it is going to attempt direct
312*cda5da8dSAndroid Build Coastguard Worker        transmission of the file.
313*cda5da8dSAndroid Build Coastguard Worker        """
314*cda5da8dSAndroid Build Coastguard Worker        return False   # No platform-specific transmission by default
315*cda5da8dSAndroid Build Coastguard Worker
316*cda5da8dSAndroid Build Coastguard Worker
317*cda5da8dSAndroid Build Coastguard Worker    def finish_content(self):
318*cda5da8dSAndroid Build Coastguard Worker        """Ensure headers and content have both been sent"""
319*cda5da8dSAndroid Build Coastguard Worker        if not self.headers_sent:
320*cda5da8dSAndroid Build Coastguard Worker            # Only zero Content-Length if not set by the application (so
321*cda5da8dSAndroid Build Coastguard Worker            # that HEAD requests can be satisfied properly, see #3839)
322*cda5da8dSAndroid Build Coastguard Worker            self.headers.setdefault('Content-Length', "0")
323*cda5da8dSAndroid Build Coastguard Worker            self.send_headers()
324*cda5da8dSAndroid Build Coastguard Worker        else:
325*cda5da8dSAndroid Build Coastguard Worker            pass # XXX check if content-length was too short?
326*cda5da8dSAndroid Build Coastguard Worker
327*cda5da8dSAndroid Build Coastguard Worker    def close(self):
328*cda5da8dSAndroid Build Coastguard Worker        """Close the iterable (if needed) and reset all instance vars
329*cda5da8dSAndroid Build Coastguard Worker
330*cda5da8dSAndroid Build Coastguard Worker        Subclasses may want to also drop the client connection.
331*cda5da8dSAndroid Build Coastguard Worker        """
332*cda5da8dSAndroid Build Coastguard Worker        try:
333*cda5da8dSAndroid Build Coastguard Worker            if hasattr(self.result,'close'):
334*cda5da8dSAndroid Build Coastguard Worker                self.result.close()
335*cda5da8dSAndroid Build Coastguard Worker        finally:
336*cda5da8dSAndroid Build Coastguard Worker            self.result = self.headers = self.status = self.environ = None
337*cda5da8dSAndroid Build Coastguard Worker            self.bytes_sent = 0; self.headers_sent = False
338*cda5da8dSAndroid Build Coastguard Worker
339*cda5da8dSAndroid Build Coastguard Worker
340*cda5da8dSAndroid Build Coastguard Worker    def send_headers(self):
341*cda5da8dSAndroid Build Coastguard Worker        """Transmit headers to the client, via self._write()"""
342*cda5da8dSAndroid Build Coastguard Worker        self.cleanup_headers()
343*cda5da8dSAndroid Build Coastguard Worker        self.headers_sent = True
344*cda5da8dSAndroid Build Coastguard Worker        if not self.origin_server or self.client_is_modern():
345*cda5da8dSAndroid Build Coastguard Worker            self.send_preamble()
346*cda5da8dSAndroid Build Coastguard Worker            self._write(bytes(self.headers))
347*cda5da8dSAndroid Build Coastguard Worker
348*cda5da8dSAndroid Build Coastguard Worker
349*cda5da8dSAndroid Build Coastguard Worker    def result_is_file(self):
350*cda5da8dSAndroid Build Coastguard Worker        """True if 'self.result' is an instance of 'self.wsgi_file_wrapper'"""
351*cda5da8dSAndroid Build Coastguard Worker        wrapper = self.wsgi_file_wrapper
352*cda5da8dSAndroid Build Coastguard Worker        return wrapper is not None and isinstance(self.result,wrapper)
353*cda5da8dSAndroid Build Coastguard Worker
354*cda5da8dSAndroid Build Coastguard Worker
355*cda5da8dSAndroid Build Coastguard Worker    def client_is_modern(self):
356*cda5da8dSAndroid Build Coastguard Worker        """True if client can accept status and headers"""
357*cda5da8dSAndroid Build Coastguard Worker        return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9'
358*cda5da8dSAndroid Build Coastguard Worker
359*cda5da8dSAndroid Build Coastguard Worker
360*cda5da8dSAndroid Build Coastguard Worker    def log_exception(self,exc_info):
361*cda5da8dSAndroid Build Coastguard Worker        """Log the 'exc_info' tuple in the server log
362*cda5da8dSAndroid Build Coastguard Worker
363*cda5da8dSAndroid Build Coastguard Worker        Subclasses may override to retarget the output or change its format.
364*cda5da8dSAndroid Build Coastguard Worker        """
365*cda5da8dSAndroid Build Coastguard Worker        try:
366*cda5da8dSAndroid Build Coastguard Worker            from traceback import print_exception
367*cda5da8dSAndroid Build Coastguard Worker            stderr = self.get_stderr()
368*cda5da8dSAndroid Build Coastguard Worker            print_exception(
369*cda5da8dSAndroid Build Coastguard Worker                exc_info[0], exc_info[1], exc_info[2],
370*cda5da8dSAndroid Build Coastguard Worker                self.traceback_limit, stderr
371*cda5da8dSAndroid Build Coastguard Worker            )
372*cda5da8dSAndroid Build Coastguard Worker            stderr.flush()
373*cda5da8dSAndroid Build Coastguard Worker        finally:
374*cda5da8dSAndroid Build Coastguard Worker            exc_info = None
375*cda5da8dSAndroid Build Coastguard Worker
376*cda5da8dSAndroid Build Coastguard Worker    def handle_error(self):
377*cda5da8dSAndroid Build Coastguard Worker        """Log current error, and send error output to client if possible"""
378*cda5da8dSAndroid Build Coastguard Worker        self.log_exception(sys.exc_info())
379*cda5da8dSAndroid Build Coastguard Worker        if not self.headers_sent:
380*cda5da8dSAndroid Build Coastguard Worker            self.result = self.error_output(self.environ, self.start_response)
381*cda5da8dSAndroid Build Coastguard Worker            self.finish_response()
382*cda5da8dSAndroid Build Coastguard Worker        # XXX else: attempt advanced recovery techniques for HTML or text?
383*cda5da8dSAndroid Build Coastguard Worker
384*cda5da8dSAndroid Build Coastguard Worker    def error_output(self, environ, start_response):
385*cda5da8dSAndroid Build Coastguard Worker        """WSGI mini-app to create error output
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Worker        By default, this just uses the 'error_status', 'error_headers',
388*cda5da8dSAndroid Build Coastguard Worker        and 'error_body' attributes to generate an output page.  It can
389*cda5da8dSAndroid Build Coastguard Worker        be overridden in a subclass to dynamically generate diagnostics,
390*cda5da8dSAndroid Build Coastguard Worker        choose an appropriate message for the user's preferred language, etc.
391*cda5da8dSAndroid Build Coastguard Worker
392*cda5da8dSAndroid Build Coastguard Worker        Note, however, that it's not recommended from a security perspective to
393*cda5da8dSAndroid Build Coastguard Worker        spit out diagnostics to any old user; ideally, you should have to do
394*cda5da8dSAndroid Build Coastguard Worker        something special to enable diagnostic output, which is why we don't
395*cda5da8dSAndroid Build Coastguard Worker        include any here!
396*cda5da8dSAndroid Build Coastguard Worker        """
397*cda5da8dSAndroid Build Coastguard Worker        start_response(self.error_status,self.error_headers[:],sys.exc_info())
398*cda5da8dSAndroid Build Coastguard Worker        return [self.error_body]
399*cda5da8dSAndroid Build Coastguard Worker
400*cda5da8dSAndroid Build Coastguard Worker
401*cda5da8dSAndroid Build Coastguard Worker    # Pure abstract methods; *must* be overridden in subclasses
402*cda5da8dSAndroid Build Coastguard Worker
403*cda5da8dSAndroid Build Coastguard Worker    def _write(self,data):
404*cda5da8dSAndroid Build Coastguard Worker        """Override in subclass to buffer data for send to client
405*cda5da8dSAndroid Build Coastguard Worker
406*cda5da8dSAndroid Build Coastguard Worker        It's okay if this method actually transmits the data; BaseHandler
407*cda5da8dSAndroid Build Coastguard Worker        just separates write and flush operations for greater efficiency
408*cda5da8dSAndroid Build Coastguard Worker        when the underlying system actually has such a distinction.
409*cda5da8dSAndroid Build Coastguard Worker        """
410*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError
411*cda5da8dSAndroid Build Coastguard Worker
412*cda5da8dSAndroid Build Coastguard Worker    def _flush(self):
413*cda5da8dSAndroid Build Coastguard Worker        """Override in subclass to force sending of recent '_write()' calls
414*cda5da8dSAndroid Build Coastguard Worker
415*cda5da8dSAndroid Build Coastguard Worker        It's okay if this method is a no-op (i.e., if '_write()' actually
416*cda5da8dSAndroid Build Coastguard Worker        sends the data.
417*cda5da8dSAndroid Build Coastguard Worker        """
418*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError
419*cda5da8dSAndroid Build Coastguard Worker
420*cda5da8dSAndroid Build Coastguard Worker    def get_stdin(self):
421*cda5da8dSAndroid Build Coastguard Worker        """Override in subclass to return suitable 'wsgi.input'"""
422*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError
423*cda5da8dSAndroid Build Coastguard Worker
424*cda5da8dSAndroid Build Coastguard Worker    def get_stderr(self):
425*cda5da8dSAndroid Build Coastguard Worker        """Override in subclass to return suitable 'wsgi.errors'"""
426*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError
427*cda5da8dSAndroid Build Coastguard Worker
428*cda5da8dSAndroid Build Coastguard Worker    def add_cgi_vars(self):
429*cda5da8dSAndroid Build Coastguard Worker        """Override in subclass to insert CGI variables in 'self.environ'"""
430*cda5da8dSAndroid Build Coastguard Worker        raise NotImplementedError
431*cda5da8dSAndroid Build Coastguard Worker
432*cda5da8dSAndroid Build Coastguard Worker
433*cda5da8dSAndroid Build Coastguard Workerclass SimpleHandler(BaseHandler):
434*cda5da8dSAndroid Build Coastguard Worker    """Handler that's just initialized with streams, environment, etc.
435*cda5da8dSAndroid Build Coastguard Worker
436*cda5da8dSAndroid Build Coastguard Worker    This handler subclass is intended for synchronous HTTP/1.0 origin servers,
437*cda5da8dSAndroid Build Coastguard Worker    and handles sending the entire response output, given the correct inputs.
438*cda5da8dSAndroid Build Coastguard Worker
439*cda5da8dSAndroid Build Coastguard Worker    Usage::
440*cda5da8dSAndroid Build Coastguard Worker
441*cda5da8dSAndroid Build Coastguard Worker        handler = SimpleHandler(
442*cda5da8dSAndroid Build Coastguard Worker            inp,out,err,env, multithread=False, multiprocess=True
443*cda5da8dSAndroid Build Coastguard Worker        )
444*cda5da8dSAndroid Build Coastguard Worker        handler.run(app)"""
445*cda5da8dSAndroid Build Coastguard Worker
446*cda5da8dSAndroid Build Coastguard Worker    def __init__(self,stdin,stdout,stderr,environ,
447*cda5da8dSAndroid Build Coastguard Worker        multithread=True, multiprocess=False
448*cda5da8dSAndroid Build Coastguard Worker    ):
449*cda5da8dSAndroid Build Coastguard Worker        self.stdin = stdin
450*cda5da8dSAndroid Build Coastguard Worker        self.stdout = stdout
451*cda5da8dSAndroid Build Coastguard Worker        self.stderr = stderr
452*cda5da8dSAndroid Build Coastguard Worker        self.base_env = environ
453*cda5da8dSAndroid Build Coastguard Worker        self.wsgi_multithread = multithread
454*cda5da8dSAndroid Build Coastguard Worker        self.wsgi_multiprocess = multiprocess
455*cda5da8dSAndroid Build Coastguard Worker
456*cda5da8dSAndroid Build Coastguard Worker    def get_stdin(self):
457*cda5da8dSAndroid Build Coastguard Worker        return self.stdin
458*cda5da8dSAndroid Build Coastguard Worker
459*cda5da8dSAndroid Build Coastguard Worker    def get_stderr(self):
460*cda5da8dSAndroid Build Coastguard Worker        return self.stderr
461*cda5da8dSAndroid Build Coastguard Worker
462*cda5da8dSAndroid Build Coastguard Worker    def add_cgi_vars(self):
463*cda5da8dSAndroid Build Coastguard Worker        self.environ.update(self.base_env)
464*cda5da8dSAndroid Build Coastguard Worker
465*cda5da8dSAndroid Build Coastguard Worker    def _write(self,data):
466*cda5da8dSAndroid Build Coastguard Worker        result = self.stdout.write(data)
467*cda5da8dSAndroid Build Coastguard Worker        if result is None or result == len(data):
468*cda5da8dSAndroid Build Coastguard Worker            return
469*cda5da8dSAndroid Build Coastguard Worker        from warnings import warn
470*cda5da8dSAndroid Build Coastguard Worker        warn("SimpleHandler.stdout.write() should not do partial writes",
471*cda5da8dSAndroid Build Coastguard Worker            DeprecationWarning)
472*cda5da8dSAndroid Build Coastguard Worker        while True:
473*cda5da8dSAndroid Build Coastguard Worker            data = data[result:]
474*cda5da8dSAndroid Build Coastguard Worker            if not data:
475*cda5da8dSAndroid Build Coastguard Worker                break
476*cda5da8dSAndroid Build Coastguard Worker            result = self.stdout.write(data)
477*cda5da8dSAndroid Build Coastguard Worker
478*cda5da8dSAndroid Build Coastguard Worker    def _flush(self):
479*cda5da8dSAndroid Build Coastguard Worker        self.stdout.flush()
480*cda5da8dSAndroid Build Coastguard Worker        self._flush = self.stdout.flush
481*cda5da8dSAndroid Build Coastguard Worker
482*cda5da8dSAndroid Build Coastguard Worker
483*cda5da8dSAndroid Build Coastguard Workerclass BaseCGIHandler(SimpleHandler):
484*cda5da8dSAndroid Build Coastguard Worker
485*cda5da8dSAndroid Build Coastguard Worker    """CGI-like systems using input/output/error streams and environ mapping
486*cda5da8dSAndroid Build Coastguard Worker
487*cda5da8dSAndroid Build Coastguard Worker    Usage::
488*cda5da8dSAndroid Build Coastguard Worker
489*cda5da8dSAndroid Build Coastguard Worker        handler = BaseCGIHandler(inp,out,err,env)
490*cda5da8dSAndroid Build Coastguard Worker        handler.run(app)
491*cda5da8dSAndroid Build Coastguard Worker
492*cda5da8dSAndroid Build Coastguard Worker    This handler class is useful for gateway protocols like ReadyExec and
493*cda5da8dSAndroid Build Coastguard Worker    FastCGI, that have usable input/output/error streams and an environment
494*cda5da8dSAndroid Build Coastguard Worker    mapping.  It's also the base class for CGIHandler, which just uses
495*cda5da8dSAndroid Build Coastguard Worker    sys.stdin, os.environ, and so on.
496*cda5da8dSAndroid Build Coastguard Worker
497*cda5da8dSAndroid Build Coastguard Worker    The constructor also takes keyword arguments 'multithread' and
498*cda5da8dSAndroid Build Coastguard Worker    'multiprocess' (defaulting to 'True' and 'False' respectively) to control
499*cda5da8dSAndroid Build Coastguard Worker    the configuration sent to the application.  It sets 'origin_server' to
500*cda5da8dSAndroid Build Coastguard Worker    False (to enable CGI-like output), and assumes that 'wsgi.run_once' is
501*cda5da8dSAndroid Build Coastguard Worker    False.
502*cda5da8dSAndroid Build Coastguard Worker    """
503*cda5da8dSAndroid Build Coastguard Worker
504*cda5da8dSAndroid Build Coastguard Worker    origin_server = False
505*cda5da8dSAndroid Build Coastguard Worker
506*cda5da8dSAndroid Build Coastguard Worker
507*cda5da8dSAndroid Build Coastguard Workerclass CGIHandler(BaseCGIHandler):
508*cda5da8dSAndroid Build Coastguard Worker
509*cda5da8dSAndroid Build Coastguard Worker    """CGI-based invocation via sys.stdin/stdout/stderr and os.environ
510*cda5da8dSAndroid Build Coastguard Worker
511*cda5da8dSAndroid Build Coastguard Worker    Usage::
512*cda5da8dSAndroid Build Coastguard Worker
513*cda5da8dSAndroid Build Coastguard Worker        CGIHandler().run(app)
514*cda5da8dSAndroid Build Coastguard Worker
515*cda5da8dSAndroid Build Coastguard Worker    The difference between this class and BaseCGIHandler is that it always
516*cda5da8dSAndroid Build Coastguard Worker    uses 'wsgi.run_once' of 'True', 'wsgi.multithread' of 'False', and
517*cda5da8dSAndroid Build Coastguard Worker    'wsgi.multiprocess' of 'True'.  It does not take any initialization
518*cda5da8dSAndroid Build Coastguard Worker    parameters, but always uses 'sys.stdin', 'os.environ', and friends.
519*cda5da8dSAndroid Build Coastguard Worker
520*cda5da8dSAndroid Build Coastguard Worker    If you need to override any of these parameters, use BaseCGIHandler
521*cda5da8dSAndroid Build Coastguard Worker    instead.
522*cda5da8dSAndroid Build Coastguard Worker    """
523*cda5da8dSAndroid Build Coastguard Worker
524*cda5da8dSAndroid Build Coastguard Worker    wsgi_run_once = True
525*cda5da8dSAndroid Build Coastguard Worker    # Do not allow os.environ to leak between requests in Google App Engine
526*cda5da8dSAndroid Build Coastguard Worker    # and other multi-run CGI use cases.  This is not easily testable.
527*cda5da8dSAndroid Build Coastguard Worker    # See http://bugs.python.org/issue7250
528*cda5da8dSAndroid Build Coastguard Worker    os_environ = {}
529*cda5da8dSAndroid Build Coastguard Worker
530*cda5da8dSAndroid Build Coastguard Worker    def __init__(self):
531*cda5da8dSAndroid Build Coastguard Worker        BaseCGIHandler.__init__(
532*cda5da8dSAndroid Build Coastguard Worker            self, sys.stdin.buffer, sys.stdout.buffer, sys.stderr,
533*cda5da8dSAndroid Build Coastguard Worker            read_environ(), multithread=False, multiprocess=True
534*cda5da8dSAndroid Build Coastguard Worker        )
535*cda5da8dSAndroid Build Coastguard Worker
536*cda5da8dSAndroid Build Coastguard Worker
537*cda5da8dSAndroid Build Coastguard Workerclass IISCGIHandler(BaseCGIHandler):
538*cda5da8dSAndroid Build Coastguard Worker    """CGI-based invocation with workaround for IIS path bug
539*cda5da8dSAndroid Build Coastguard Worker
540*cda5da8dSAndroid Build Coastguard Worker    This handler should be used in preference to CGIHandler when deploying on
541*cda5da8dSAndroid Build Coastguard Worker    Microsoft IIS without having set the config allowPathInfo option (IIS>=7)
542*cda5da8dSAndroid Build Coastguard Worker    or metabase allowPathInfoForScriptMappings (IIS<7).
543*cda5da8dSAndroid Build Coastguard Worker    """
544*cda5da8dSAndroid Build Coastguard Worker    wsgi_run_once = True
545*cda5da8dSAndroid Build Coastguard Worker    os_environ = {}
546*cda5da8dSAndroid Build Coastguard Worker
547*cda5da8dSAndroid Build Coastguard Worker    # By default, IIS gives a PATH_INFO that duplicates the SCRIPT_NAME at
548*cda5da8dSAndroid Build Coastguard Worker    # the front, causing problems for WSGI applications that wish to implement
549*cda5da8dSAndroid Build Coastguard Worker    # routing. This handler strips any such duplicated path.
550*cda5da8dSAndroid Build Coastguard Worker
551*cda5da8dSAndroid Build Coastguard Worker    # IIS can be configured to pass the correct PATH_INFO, but this causes
552*cda5da8dSAndroid Build Coastguard Worker    # another bug where PATH_TRANSLATED is wrong. Luckily this variable is
553*cda5da8dSAndroid Build Coastguard Worker    # rarely used and is not guaranteed by WSGI. On IIS<7, though, the
554*cda5da8dSAndroid Build Coastguard Worker    # setting can only be made on a vhost level, affecting all other script
555*cda5da8dSAndroid Build Coastguard Worker    # mappings, many of which break when exposed to the PATH_TRANSLATED bug.
556*cda5da8dSAndroid Build Coastguard Worker    # For this reason IIS<7 is almost never deployed with the fix. (Even IIS7
557*cda5da8dSAndroid Build Coastguard Worker    # rarely uses it because there is still no UI for it.)
558*cda5da8dSAndroid Build Coastguard Worker
559*cda5da8dSAndroid Build Coastguard Worker    # There is no way for CGI code to tell whether the option was set, so a
560*cda5da8dSAndroid Build Coastguard Worker    # separate handler class is provided.
561*cda5da8dSAndroid Build Coastguard Worker    def __init__(self):
562*cda5da8dSAndroid Build Coastguard Worker        environ= read_environ()
563*cda5da8dSAndroid Build Coastguard Worker        path = environ.get('PATH_INFO', '')
564*cda5da8dSAndroid Build Coastguard Worker        script = environ.get('SCRIPT_NAME', '')
565*cda5da8dSAndroid Build Coastguard Worker        if (path+'/').startswith(script+'/'):
566*cda5da8dSAndroid Build Coastguard Worker            environ['PATH_INFO'] = path[len(script):]
567*cda5da8dSAndroid Build Coastguard Worker        BaseCGIHandler.__init__(
568*cda5da8dSAndroid Build Coastguard Worker            self, sys.stdin.buffer, sys.stdout.buffer, sys.stderr,
569*cda5da8dSAndroid Build Coastguard Worker            environ, multithread=False, multiprocess=True
570*cda5da8dSAndroid Build Coastguard Worker        )
571