1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh"""Base classes for server/gateway implementations"""
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom types import StringType
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom util import FileWrapper, guess_scheme, is_hop_by_hop
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom headers import Headers
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport sys, os, time
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh__all__ = ['BaseHandler', 'SimpleHandler', 'BaseCGIHandler', 'CGIHandler']
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehtry:
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    dict
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehexcept NameError:
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def dict(items):
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        d = {}
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        for k,v in items:
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            d[k] = v
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return d
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Uncomment for 2.2 compatibility.
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#try:
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#    True
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#    False
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#except NameError:
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#    True = not None
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#    False = not True
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Weekday and month names for HTTP date/time formatting; always English!
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_weekdayname = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh_monthname = [None, # Dummy so we can use 1-based month numbers
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              "Jan", "Feb", "Mar", "Apr", "May", "Jun",
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef format_date_time(timestamp):
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        _weekdayname[wd], day, _monthname[month], year, hh, mm, ss
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    )
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass BaseHandler:
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """Manage the invocation of a WSGI application"""
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Configuration parameters; can override per-subclass or per-instance
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    wsgi_version = (1,0)
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    wsgi_multithread = True
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    wsgi_multiprocess = True
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    wsgi_run_once = False
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    origin_server = True    # We are transmitting direct to client
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    http_version  = "1.0"   # Version that should be used for response
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    server_software = None  # String name of server software, if any
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # os_environ is used to supply configuration from the OS environment:
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # by default it's a copy of 'os.environ' as of import time, but you can
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # override this in e.g. your __init__ method.
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    os_environ = dict(os.environ.items())
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Collaborator classes
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    wsgi_file_wrapper = FileWrapper     # set to None to disable
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    headers_class = Headers             # must be a Headers-like class
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Error handling (also per-subclass or per-instance)
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    traceback_limit = None  # Print entire traceback to self.get_stderr()
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    error_status = "500 Internal Server Error"
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    error_headers = [('Content-Type','text/plain')]
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    error_body = "A server error occurred.  Please contact the administrator."
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # State variables (don't mess with these)
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    status = result = None
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    headers_sent = False
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    headers = None
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    bytes_sent = 0
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def run(self, application):
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Invoke the application"""
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Note to self: don't move the close()!  Asynchronous servers shouldn't
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # call close() from finish_response(), so if you close() anywhere but
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # the double-error branch here, you'll break asynchronous servers by
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # prematurely closing.  Async servers must return from 'run()' without
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # closing if there might still be output to iterate over.
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.setup_environ()
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.result = application(self.environ, self.start_response)
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.finish_response()
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except:
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.handle_error()
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except:
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # If we get an error handling an error, just give up already!
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.close()
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                raise   # ...and let the actual server figure it out.
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def setup_environ(self):
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Set up the environment for one request"""
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env = self.environ = self.os_environ.copy()
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.add_cgi_vars()
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.input']        = self.get_stdin()
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.errors']       = self.get_stderr()
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.version']      = self.wsgi_version
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.run_once']     = self.wsgi_run_once
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.url_scheme']   = self.get_scheme()
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.multithread']  = self.wsgi_multithread
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        env['wsgi.multiprocess'] = self.wsgi_multiprocess
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.wsgi_file_wrapper is not None:
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            env['wsgi.file_wrapper'] = self.wsgi_file_wrapper
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.origin_server and self.server_software:
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            env.setdefault('SERVER_SOFTWARE',self.server_software)
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def finish_response(self):
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Send any iterable data, then close self and the iterable
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Subclasses intended for use in asynchronous servers will
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        want to redefine this method, such that it sets up callbacks
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        in the event loop to iterate over the data, and to call
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        'self.close()' once the response is finished.
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not self.result_is_file() or not self.sendfile():
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                for data in self.result:
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.write(data)
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.finish_content()
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.close()
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_scheme(self):
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Return the URL scheme being used"""
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return guess_scheme(self.environ)
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_content_length(self):
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Compute Content-Length or switch to chunked encoding if possible"""
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            blocks = len(self.result)
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except (TypeError,AttributeError,NotImplementedError):
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if blocks==1:
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.headers['Content-Length'] = str(self.bytes_sent)
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # XXX Try for chunked encoding if origin server and client is 1.1
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def cleanup_headers(self):
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Make any necessary header changes or defaults
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Subclasses can extend this to add other defaults.
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if 'Content-Length' not in self.headers:
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.set_content_length()
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def start_response(self, status, headers,exc_info=None):
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """'start_response()' callable as specified by PEP 333"""
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if exc_info:
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.headers_sent:
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    # Re-raise original exception if headers sent
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    raise exc_info[0], exc_info[1], exc_info[2]
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            finally:
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                exc_info = None        # avoid dangling circular ref
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif self.headers is not None:
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raise AssertionError("Headers already set!")
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert type(status) is StringType,"Status must be a string"
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert len(status)>=4,"Status must be at least 4 characters"
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert int(status[:3]),"Status message must begin w/3-digit code"
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert status[3]==" ", "Status message must have a space after code"
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if __debug__:
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            for name,val in headers:
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                assert type(name) is StringType,"Header names must be strings"
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                assert type(val) is StringType,"Header values must be strings"
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                assert not is_hop_by_hop(name),"Hop-by-hop headers not allowed"
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.status = status
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.headers = self.headers_class(headers)
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.write
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def send_preamble(self):
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Transmit version/status/date/server, via self._write()"""
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.origin_server:
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.client_is_modern():
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if 'Date' not in self.headers:
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self._write(
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        'Date: %s\r\n' % format_date_time(time.time())
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    )
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.server_software and 'Server' not in self.headers:
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self._write('Server: %s\r\n' % self.server_software)
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self._write('Status: %s\r\n' % self.status)
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def write(self, data):
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """'write()' callable as specified by PEP 333"""
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        assert type(data) is StringType,"write() argument must be string"
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.status:
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            raise AssertionError("write() before start_response()")
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif not self.headers_sent:
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Before the first output, send the stored headers
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.bytes_sent = len(data)    # make sure we know content-length
212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.send_headers()
213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.bytes_sent += len(data)
215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # XXX check Content-Length and truncate if too many bytes written?
217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._write(data)
218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._flush()
219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def sendfile(self):
222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Platform-specific file transmission
223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Override this method in subclasses to support platform-specific
225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        file transmission.  It is only called if the application's
226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return iterable ('self.result') is an instance of
227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        'self.wsgi_file_wrapper'.
228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        This method should return a true value if it was able to actually
230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        transmit the wrapped file-like object using a platform-specific
231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        approach.  It should return a false value if normal iteration
232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        should be used instead.  An exception can be raised to indicate
233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        that transmission was attempted, but failed.
234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        NOTE: this method should call 'self.send_headers()' if
236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        'self.headers_sent' is false and it is going to attempt direct
237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        transmission of the file.
238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return False   # No platform-specific transmission by default
240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def finish_content(self):
243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Ensure headers and content have both been sent"""
244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.headers_sent:
245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # Only zero Content-Length if not set by the application (so
246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # that HEAD requests can be satisfied properly, see #3839)
247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.headers.setdefault('Content-Length', "0")
248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.send_headers()
249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass # XXX check if content-length was too short?
251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def close(self):
253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Close the iterable (if needed) and reset all instance vars
254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Subclasses may want to also drop the client connection.
256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if hasattr(self.result,'close'):
259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.result.close()
260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.result = self.headers = self.status = self.environ = None
262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.bytes_sent = 0; self.headers_sent = False
263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def send_headers(self):
266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Transmit headers to the client, via self._write()"""
267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.cleanup_headers()
268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.headers_sent = True
269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.origin_server or self.client_is_modern():
270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.send_preamble()
271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self._write(str(self.headers))
272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def result_is_file(self):
275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """True if 'self.result' is an instance of 'self.wsgi_file_wrapper'"""
276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        wrapper = self.wsgi_file_wrapper
277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return wrapper is not None and isinstance(self.result,wrapper)
278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def client_is_modern(self):
281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """True if client can accept status and headers"""
282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9'
283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def log_exception(self,exc_info):
286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Log the 'exc_info' tuple in the server log
287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Subclasses may override to retarget the output or change its format.
289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            from traceback import print_exception
292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            stderr = self.get_stderr()
293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            print_exception(
294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                exc_info[0], exc_info[1], exc_info[2],
295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.traceback_limit, stderr
296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            )
297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            stderr.flush()
298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        finally:
299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            exc_info = None
300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def handle_error(self):
302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Log current error, and send error output to client if possible"""
303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.log_exception(sys.exc_info())
304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.headers_sent:
305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.result = self.error_output(self.environ, self.start_response)
306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.finish_response()
307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # XXX else: attempt advanced recovery techniques for HTML or text?
308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def error_output(self, environ, start_response):
310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """WSGI mini-app to create error output
311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        By default, this just uses the 'error_status', 'error_headers',
313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        and 'error_body' attributes to generate an output page.  It can
314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        be overridden in a subclass to dynamically generate diagnostics,
315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        choose an appropriate message for the user's preferred language, etc.
316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        Note, however, that it's not recommended from a security perspective to
318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        spit out diagnostics to any old user; ideally, you should have to do
319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        something special to enable diagnostic output, which is why we don't
320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        include any here!
321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        start_response(self.error_status,self.error_headers[:],sys.exc_info())
323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return [self.error_body]
324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Pure abstract methods; *must* be overridden in subclasses
327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _write(self,data):
329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Override in subclass to buffer data for send to client
330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        It's okay if this method actually transmits the data; BaseHandler
332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        just separates write and flush operations for greater efficiency
333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        when the underlying system actually has such a distinction.
334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        raise NotImplementedError
336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _flush(self):
338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Override in subclass to force sending of recent '_write()' calls
339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        It's okay if this method is a no-op (i.e., if '_write()' actually
341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        sends the data.
342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        raise NotImplementedError
344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_stdin(self):
346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Override in subclass to return suitable 'wsgi.input'"""
347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        raise NotImplementedError
348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_stderr(self):
350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Override in subclass to return suitable 'wsgi.errors'"""
351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        raise NotImplementedError
352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def add_cgi_vars(self):
354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Override in subclass to insert CGI variables in 'self.environ'"""
355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        raise NotImplementedError
356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass SimpleHandler(BaseHandler):
359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """Handler that's just initialized with streams, environment, etc.
360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    This handler subclass is intended for synchronous HTTP/1.0 origin servers,
362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    and handles sending the entire response output, given the correct inputs.
363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Usage::
365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        handler = SimpleHandler(
367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            inp,out,err,env, multithread=False, multiprocess=True
368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        )
369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        handler.run(app)"""
370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self,stdin,stdout,stderr,environ,
372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        multithread=True, multiprocess=False
373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    ):
374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdin = stdin
375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdout = stdout
376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stderr = stderr
377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.base_env = environ
378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.wsgi_multithread = multithread
379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.wsgi_multiprocess = multiprocess
380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_stdin(self):
382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.stdin
383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_stderr(self):
385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.stderr
386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def add_cgi_vars(self):
388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.environ.update(self.base_env)
389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _write(self,data):
391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdout.write(data)
392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._write = self.stdout.write
393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def _flush(self):
395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.stdout.flush()
396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._flush = self.stdout.flush
397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass BaseCGIHandler(SimpleHandler):
400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """CGI-like systems using input/output/error streams and environ mapping
402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Usage::
404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        handler = BaseCGIHandler(inp,out,err,env)
406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        handler.run(app)
407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    This handler class is useful for gateway protocols like ReadyExec and
409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    FastCGI, that have usable input/output/error streams and an environment
410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    mapping.  It's also the base class for CGIHandler, which just uses
411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    sys.stdin, os.environ, and so on.
412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    The constructor also takes keyword arguments 'multithread' and
414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    'multiprocess' (defaulting to 'True' and 'False' respectively) to control
415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    the configuration sent to the application.  It sets 'origin_server' to
416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    False (to enable CGI-like output), and assumes that 'wsgi.run_once' is
417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    False.
418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    origin_server = False
421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass CGIHandler(BaseCGIHandler):
424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """CGI-based invocation via sys.stdin/stdout/stderr and os.environ
426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Usage::
428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        CGIHandler().run(app)
430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    The difference between this class and BaseCGIHandler is that it always
432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    uses 'wsgi.run_once' of 'True', 'wsgi.multithread' of 'False', and
433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    'wsgi.multiprocess' of 'True'.  It does not take any initialization
434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    parameters, but always uses 'sys.stdin', 'os.environ', and friends.
435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    If you need to override any of these parameters, use BaseCGIHandler
437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    instead.
438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    wsgi_run_once = True
441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Do not allow os.environ to leak between requests in Google App Engine
442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # and other multi-run CGI use cases.  This is not easily testable.
443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # See http://bugs.python.org/issue7250
444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    os_environ = {}
445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self):
447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        BaseCGIHandler.__init__(
448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self, sys.stdin, sys.stdout, sys.stderr, dict(os.environ.items()),
449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            multithread=False, multiprocess=True
450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        )
451