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